Skip to content
This repository has been archived by the owner on May 7, 2020. It is now read-only.

Initial contribution of semantic metadata support #6288

Merged
merged 1 commit into from
Oct 11, 2018

Conversation

kaikreuzer
Copy link
Contributor

@kaikreuzer kaikreuzer commented Sep 27, 2018

This is the first code for defining a semantic model that is driven and maintained through tags on items. It is the outcome of the discussion at #1093 and explicitly an implementation of what has been sketched out in #1093 (comment).

While working on it, I made a few small edits and amendments to the discussed version. To give an overview, let me start with a visualisation of the chosen model:

download

This is very much in line with the Brick Schema with the main difference that "Property" (in Brick "MeasurementProperty") has been introduced with a "relatesTo" relation from "Point" - similar to what I have suggested in BuildSysUniformMetadata/GroundTruth#2. Having Properties that can be referred to, makes the number of different Point tags much smaller. Note also that I tried to avoid the expression "TagSet" so far as my feeling is that this would rather irritate people here as "Tags" in the Brick sense (single segments of a full id with underscores) are not used on their own, but always as a "fully qualified" tag only.

The tag library is pretty much in line with what we defined in the wiki, with a few adaptions:

  • I have left away the "Purpose" tags up to know as this concept does not exist in Brick and it is imho the one with the lowest prio for us
  • I have added a hierarchy for Points (fully inline with Brick), which defines the sub-types Command (our previous "Control", Sensor (previously "Measurement"), Alarm, Setpoint and Status.
  • Volume and ColorTemperature are now a Property and not a Point
  • Switch/Dimmer/Color have become "Control" Points
  • Home/Office Location types have been removed as they are rather a purpose of the location than a type

The tags are maintained in a csv file from which all classes can be easily generated through a small script - this should simplify the maintenance significantly and also allow us to do adaptions to whatever we might want to have generated from it.

The main feature of this PR is a new metadata provider, which adds a "semantics" namespace as suggested in #1093 (comment). I decided against adding the synonyms here, but think that synonyms should be independent of semantics and can be simply provided by a separate metadata namespace "synonyms". Here's an example item file that a user could define:

Group           Home                     "Our Home"         <house>                                        ["Location"]

Group           GF                       "Ground Floor"     <groundfloor>     (Home)                       ["Floor"]
Group           FF                       "First Floor"      <firstfloor>      (Home)                       ["Floor"]

Group           GF_Bedroom               "Bedroom"          <bedroom>         (Home, GF)                   ["Bedroom"]
Group           GF_LivingRoom            "Living Room"      <sofa>            (Home, GF)                   ["Room"]
Group           FF_GuestRoom             "Guest Room"       <parents_4_3>     (Home, FF)                   ["Room"]
Group           FF_KidsRoom              "Kids Room"        <girl_3>          (Home, FF)                   ["Room"]

Switch          GF_Bedroom_Light         "Light"            <light>           (GF_Bedroom, gLight)         ["Light"] { synonyms="Lamp,Ceiling light,Lights" }
Number          GF_Bedroom_Temperature   "Temperature"      <temperature>     (GF_Bedroom, gTemperature)   ["Sensor", "Temperature"]
Rollershutter   GF_LivingRoom_Shutter    "Roller Shutter"   <rollershutter>   (GF_LivingRoom, gShutter)    ["Blinds"]
Contact         GF_LivingRoom_Door       "Door"             <door>            (GF_LivingRoom, gDoor)       ["OpenState"]
Switch          GF_LivingRoom_Light      "Light"            <light>           (GF_LivingRoom, gLight)      ["Light"]
Switch          FF_GuestRoom_Motion      "Motion Sensor"    <motion>          (FF_GuestRoom, gMotion)      ["Sensor", "Presence"]
Contact         FF_KidsRoom_Window       "Window"           <window>          (FF_KidsRoom, gWindow)       ["OpenState"]

Group:Switch:OR(ON, OFF)           gLight         "Light"            <light>           (Home)
Group:Number:AVG                   gTemperature   "Temperature"      <temperature>     (Home)
Group:Switch:OR(ON, OFF)           gMotion        "Motion Sensor"    <motion>          (Home)
Group:Contact:OR(OPEN, CLOSED)     gWindow        "Window"           <window>          (Home)
Group:Rollershutter:OR(UP, DOWN)   gShutter       "Roller Shutter"   <rollershutter>   (Home)
Group:Contact:OR(OPEN, CLOSED)     gDoor          "Door"             <door>            (Home)

Note that the semantics data is not specified by the user here, but it is constructed by the framework on the basis of the item information - i.e. its containment relations and its tags. A single ["Light"] tag is enough to deduce that the item is a "Command Point for Light".

The resulting metadata looks e.g. like

    "link": "http://localhost:8080/rest/items/GF_Bedroom_Light",
    "metadata": {
        "synonyms": {
            "value": "Lamp,Ceiling light,Lights"
        },
        "semantics": {
            "value": "Point_Command",
            "config": {
                "relatesTo": "Property_Light",
                "hasLocation": "GF_Bedroom"
            }
        }
    }

for GF_Bedroom_Light.

This is meant as a first validation of the approach, specifically for @ghys.
There are clearly still many open issues to address:

  • This is read-only data, we cannot yet do specific queries on semantics
  • There are no synonyms defined yet for our tags. Imho they would be static information, so those could be added to the csv file and we can generated mapping files for different purposes (HLI, JS UIs, etc.)
  • isPointOf currently only points to items, but not to Things.
  • It is still unclear to me to what extend we should regard the category information on items.
  • I wonder whether "Property" should be split into "Property" and "Resource" - resources being air, water, oil, etc. while properties would be temperature, speed, volume, etc, i.e. the stuff that you measure/control about a resource. Currently, it feels like a weird mix, but I am also afraid of adding to much complexity, if this is split.

Signed-off-by: Kai Kreuzer kai@openhab.org

@ghys
Copy link
Contributor

ghys commented Sep 28, 2018

Seems like a solid foundation, and rather friendly for the user, I like it!

Some initial remarks and questions:

Note that the synonyms data is not specified by the user here, but it is constructed by the framework on the basis of the item information

I think you meant "semantics" not "synonyms"?

Group           GF                       "Ground Floor"     <groundfloor>     (Home)                       ["Floor"]
Group           FF                       "First Floor"      <firstfloor>      (Home)                       ["Floor"]

Maybe a hierarchy under Location_Indoor_Floor is necessary here to distinguish floors from one another? Ground Floor, First Floor, (Second floor?, more?), Attic, Basement/Cellar...

There are no synonyms defined yet for our tags. Imho they would be static information, so those could be added to the csv file and we can generated mapping files for different purposes (HLI, JS UIs, etc.)

Open question related to NLP: in my equivalent here https://github.com/ghys/habot/blob/master/src/main/resources/tagattributes.properties I included plurals, because it was way easier than e.g. using OpenNLP to perform lemmatization beforehand. How would you handle that, include the lemmatization by the framework (or providing plurals as synonyms) or expect the caller to do it and provide the lemma? Implementations might or might not get the lemma e.g. from a cloud-based NLP service, or have access to a lemmatizer.

isPointOf currently only points to items, but not to Things.

In case of Things, would that be defined at the channel level?

It is still unclear to me to what extend we should regard the category information on items.

I think it's a double edged sword, on one hand, in many cases it provides the same semantic meaning as the tag, thus would make the tag redundant (and prevent the need to alter existing configurations). On the other hand, I suspect users frequently assume what's inside brackets has no semantic meaning at all and is just the default icon to display in sitemaps for the item, so they may choose only based on what icon they fancy better.
The openHAB docs are misleading in that regard and even the demo setup is guilty of it.

@ghys
Copy link
Contributor

ghys commented Sep 28, 2018

There are no synonyms defined yet for our tags. Imho they would be static information, so those could be added to the csv file and we can generated mapping files for different purposes (HLI, JS UIs, etc.)

How would you handle i18n and l10n of those synonyms?

MetadataKey key = new MetadataKey(NAMESPACE, item.getName());
Map<String, Object> configuration = new HashMap<>();
Class<? extends Tag> type = tagService.getSemanticType(item);
if (type != null) {
Copy link
Contributor

@ghys ghys Sep 28, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't process the hierarchy unless a tag is directly applied on the item, so it doesn't handle situations like this:

Group gGF           "Ground Floor"  <groundfloor> ["Floor"]
Group GF_Corridor   "Corridor"      <corridor>  (gGF) ["Corridor"]
Group:Switch:OR(ON, OFF)        Lights      "All Lights [(%d)]"                 <lightbulb> ["Lightbulb"]
Switch Light_GF_Corridor_Ceiling    "Downstairs Corridor"       (GF_Corridor, Lights)

In this case I would expect something like this:

    "link": "http://localhost:8080/rest/items/Light_GF_Corridor_Ceiling",
    "metadata": {
      "semantics": {
        "value": "Equipment_Lightbulb", // not actually sure how it would come up with it - prone to conflicts
        "config": {
          "isPartOf": "Lights",
          "hasLocation": "GF_Corridor"
        }
      }
    },

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You will notice that I purposefully didn't add ANY tags to the functional group items (Lights, Heatings, etc.) in my example above. I think this can easily get us into trouble. It would actually mean "This item is a lightbulb", while you actually intend to express "All items in this group are lightbulbs". I think it is the safer way to require all items to be individually tagged accordingly.
MAYBE we can do an exception for Point (i.e. real functionality) types, because they will never(?) be assigned to a group item. So if they are found on a group item, once could declare that this means that it should be applied to all members.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is the safer way to require all items to be individually tagged accordingly.

I'm still not 100% happy with this from a user convenience perspective :) ...but I recall a prior conversation about assuming groups as an entity by itself vs. groups as a set of similar items so I understand.
Not sure about introducing too many exceptions, it would just add to the confusion.

@kaikreuzer
Copy link
Contributor Author

I think you meant "semantics" not "synonyms"?

Sure, sorry, I've corrected it above.

Maybe a hierarchy under Location_Indoor_Floor is necessary here

Yes, on the wiki, we actually have that already. Will add it to the csv, I missed it there.

Open question related to NLP: I included plurals

Ah, I didn't know yet that Deck is the plural of Terrace 😛 .
I think I would tend to add plurals to the synonyms in the tag library (which are the types), so that "turn of the light" and "turn of the lights" are both easily covered.
For the synonyms a user defines on an item, I am not sure we would at all need plurals - those are individual instances, such as "Amy's room"; you will never have the situation that the user will ask something to be done in "Amy's rooms", right?

In case of Things, would that be defined at the channel level?

No, my plan was to simply link to a ThingUID here as Things also have a defined location and a user-provided label (but no synonyms 😟), so that could be useful without requiring the creation of group items that 1:1 correspond to a Thing.

@kaikreuzer
Copy link
Contributor Author

so they may choose only based on what icon they fancy better.

Yes, that's how it's used (and to be fair, that's also what it originates from - the "category" was once called "icon"). But for exactly this reason, I am also reluctant to include this information into the semantics. The only exception might be the category on a Thing itself (which should reflect an equipment tag).

How would you handle i18n and l10n of those synonyms?

I thought about simple property files that could be maintained. We could have a file like your tagattributes.properties generated with the english texts and then have that localised in separate files. Question is whether those should be packaged into clients like HABot at build time or if we should serve them via HTTP to request at runtime. Any preferences?

@ghys
Copy link
Contributor

ghys commented Sep 28, 2018

Will add it to the csv, I missed it there.

And if you want to be thorough, Bathroom and Toilet are missing as well.

Ah, I didn't know yet that Deck is the plural of Terrace 😛 .

:) People usually don't have multiple terraces or first floors (unless they're lucky!), but they might have multiple smoke detectors and might ask for all of them in a sentence. Synonyms ("downstairs"), plural forms, acronyms, abbreviations... everything that might be reasonably encountered and extracted from natural language in raw form that would be referring to some entity class in the model.

For the synonyms a user defines on an item, I am not sure we would at all need plurals

Yes, even if there could sometimes be plurals (like "guest rooms", "plant sensors" or even brand names and the like - "mi floras", "roombas"...) for user-supplied synonyms it's fair to assume it's the responsibility of the user to provide all forms. Lemmatization is not easy...!

Question is whether those should be packaged into clients like HABot at build time or if we should serve them via HTTP to request at runtime. Any preferences?

I think having it inside the framework would be a good thing so clients would simply supply their extracted natural language entities and expect a set of matching items. I don't know if there's actually a need to provide them in a HTTP API. The entity extraction from natural language is done on the server, not the client, so a regular service would do, or even this could be part of the upcoming querying facilities.

In HABot the key method to reimplement is AbstractItemIntentInterpreter::findItems(Intent intent), that is, given a object ("what", which could be a Point, Equipment or Property) and/or a location ("where"), return the corresponding set of matching items (if both are provided, consider both individually and do the intersection of both sets).

@kaikreuzer
Copy link
Contributor Author

Hey @ghys, sorry for the late reply, but I had to do quite some further coding on this. Here's some update:

And if you want to be thorough, Bathroom and Toilet are missing as well.

I've added a couple of further tags, but after reading this, I refrained from adding "Toilet"...

everything that might be reasonably encountered and extracted from natural language in raw form that would be referring to some entity class in the model.

I have added a "synonym" column for the entity classes (tags) in the csv and I am now also generating property files from this, which can then be easily translated into other languages.
You can query tags classes by their label/synonyms now (in a given locale).

for user-supplied synonyms it's fair to assume it's the responsibility of the user to provide all forms.

Yes, and I guess for those cases, the user could also use group items with functions to add such tags and synonyms; but let us better investigate this as a later step, there might be a few corner cases to consider...

I think having it inside the framework would be a good thing

Ok, in Java code, you have the SemanticTags class and the SemanticsService available now, as well as the SemanticsPredicates - we can add all sorts of required methods in those classes to make life easy for consumers.

given a object ("what", which could be a Point, Equipment or Property) and/or a location ("where"), return the corresponding set of matching items

I have started with querying for the items within a given location. Please have a look if this is about what you need and we can add similar methods for querying equipment/points. I'd think we should keep point and equipment queries separate in the framework - if HABot currently simply takes the union of the results, that should be fine, but I wouldn't want to create any "query for object" in the framework.

Let me know if this is something you could start with - I'd then declare the PR to be good enough for an initial merge (after review by some committer of course). My further time to work on this is unfortunately extremely limited, so I hope it is not totally unusable ;-)

@kaikreuzer kaikreuzer changed the title [WIP] initial contribution of semantic metadata support Initial contribution of semantic metadata support Oct 1, 2018
ghys added a commit to openhab/org.openhab.ui.habot that referenced this pull request Oct 2, 2018
Related to eclipse-archived/smarthome#6288.

Signed-off-by: Yannick Schaus <habpanel@schaus.net>
@ghys
Copy link
Contributor

ghys commented Oct 2, 2018

I've added a couple of further tags, but after reading this, I refrained from adding "Toilet"...

It's still a room most houses have... :) "Restroom" then maybe?
I don't know how far we could go with locations - "Pool", "Closet", "Laundry Room" come to mind...

I'd think we should keep point and equipment queries separate in the framework - if HABot currently simply takes the union of the results, that should be fine, but I wouldn't want to create any "query for object" in the framework.

Yes of course, "object" is purely an HABot concept now (should be considered in a grammatic sense). Maybe I'll try to alter the training data so it recognizes the proper type "Point", "Equipment" etc. instead - but it makes little difference and could reduce accuracy.

Let me know if this is something you could start with - I'd then declare the PR to be good enough for an initial merge (after review by some committer of course). My further time to work on this is unfortunately extremely limited, so I hope it is not totally unusable ;-)

It seems to be usable, I have an early implementation of a SemanticsItemResolver at https://github.com/ghys/habot/pull/24.
...And it looks promising, already working for basic stuff!

image

My further time to work on this is unfortunately extremely limited

Sure, now that the general direction is set, if there is a need for adjustments or extensions I will file follow-up PRs.

@ghys
Copy link
Contributor

ghys commented Oct 2, 2018

@kaikreuzer just so I understand: with the current model, a single item cannot be both an Equipment and a Point, right?
For instance this is not allowed (or will have unpredictable results):

Contact Garage_Door <garagedoor> (Garden, Window) ["GarageDoor", "OpenState"]

The way of modelling this to have both would then be a Group representing the equipment ("GarageDoor") with one member representing its "OpenState" point?

@kaikreuzer
Copy link
Contributor Author

...And it looks promising, already working for basic stuff!

Wow, you are amazing 🥇

The way of modelling this to have both would then be a Group representing the equipment ("GarageDoor") with one member representing its "OpenState" point?

Correct and far from user-friendly, I agree.
But two comments on that:

  1. A point does not have to be associated with an equipment, it can exist on its own. If the user labels it "garage" (or adds such a synonym), it would be all fine.
  2. I was thinking about defining "single point equipments" - i.e. allowing something like you describe. We would define the item to be a Point, but still have a "isPointOf" relation to a virtual Equipment (not sure what value we would give it? Maybe just referencing its type?). But let's keep that for a follow-up and work with (1) for the start.

@ghys
Copy link
Contributor

ghys commented Oct 2, 2018

If the user labels it "garage" (or adds such a synonym), it would be all fine.

Yes but I think users would also want to query specific classes of equipments, like "show me all the doors" - this wouldn't work in that case because the information that this item represents a door is lost. They might also choose to omit the Point tag, but then "show me all the contact sensors" isn't possible anymore.
(It seems to me users refer more often to equipments than to points in natural language.)

I was thinking about defining "single point equipments" - i.e. allowing something like you describe. We would define the item to be a Point, but still have a "isPointOf" relation to a virtual Equipment (not sure what value we would give it? Maybe just referencing its type?).

Could work if the querying supports it and it's in line with the Brick schema (or if it's okay to derive from it a little bit).
Or, allowing an item to have both a Point and an Equipment class at the same time:

    "metadata": {
      "semantics": {
        "value": "Point_Status_OpenState,Equipment_Door_Garagedoor",
        "config": {
          "hasLocation": "GF_Corridor",
          "isPointOf": "self",
          "hasPoint": "self",
        }
      }
    },

(isPointOf/pointOf could be omitted, they are implicit, just an example).
I'm really not too sure it wouldn't lead to problems or even if it makes sense at all though - and it would change the APIs significantly.

ghys added a commit to ghys/smarthome that referenced this pull request Oct 4, 2018
This implements eclipse-archived#6288 (comment):

Allows items to carry multiple semantic types e.g.
`["Equipment_Door_GarageDoor", "Point_OpenState"]`
and also to represent multiple properties e.g.
`["Property_Water", "Property_Pressure"]`

Relations are only expressed in metadata if they are relations
to other items - "implied" relations between tags within the item
itself don't appear in metadata.

Signed-off-by: Yannick Schaus <eclipse@schaus.net>
@ghys
Copy link
Contributor

ghys commented Oct 4, 2018

@kaikreuzer I have given it some thought and I think rather than enforcing an 1 Brick entity <=> 1 ESH item principle, items should be allowed to have multiple "traits" i.e. carry multiple types.

Here are some arguments:

  • Nothing prevents users from applying the tags they want to their items, even if they might be incompatible, sometimes they're not (see the "Equipment with only one Point" example above); and the current implementations of SemanticTags::getSemanticType and SemanticTags::getProperty are IMHO problematic because they will return the first encountered matching tag, therefore the result is unpredictable if they are several of them are applied. Reflecting exactly the tags the user has actually applied is arguably better
  • It prevents the need for useless additional Groups with only one member and the need for "virtual equipments" and the like which might be difficult to understand
  • It isn't a break from the Brick schema, if you consider items with multiple types/properties to be an opaque group of Brick entities related to each other
    For example:
Contact FrontDoor_Contact_Sensor ["FrontDoor", "Equipment_Sensor", "OpenState"]

is to be interpreted as:

[Equipment_Door_FrontDoor] <--isPartOf-- [Equipment_Sensor] <--isPointOf-- [Point_OpenState]

in a single item.

  • it allows items to appear successfully in different queries:
Contact Window_GF_Frontdoor     "Frontdoor [MAP(en.map):%s]"     <frontdoor>  (GF_Corridor, Windows)            ["FrontDoor", "Equipment_Sensor", "OpenState"]
Contact Window_GF_Kitchen       "Kitchen [MAP(en.map):%s]"                    (GF_Kitchen, Windows)             ["Window", "Equipment_Sensor", "OpenState"]
Contact Window_GF_Living        "Terrace door [MAP(en.map):%s]"  <door>       (GF_Living, Windows)              ["Door", "Equipment_Sensor", "OpenState"]
Contact Window_GF_Toilet        "Toilet [MAP(en.map):%s]"                     (GF_Toilet, Windows)              ["Window", "Equipment_Sensor", "OpenState"]
Contact Window_FF_Bath          "Bath [MAP(en.map):%s]"                       (FF_Bath, Windows)                ["Window", "Equipment_Sensor", "OpenState"]
Contact Window_FF_Bed           "Bedroom [MAP(en.map):%s]"                    (FF_Bed, Windows)                 ["Window", "Equipment_Sensor", "OpenState"]
Contact Window_FF_Office_Window "Office Window [MAP(en.map):%s]"              (FF_Office, Windows)              ["Window", "Equipment_Sensor", "OpenState"]
Contact Window_FF_Office_Door   "Balcony Door [MAP(en.map):%s]"  <door>       (FF_Office, Windows)              ["Door", "OpenState"] { synonyms="Balcony Door" }
Contact Garage_Door             "Garage Door [MAP(en.map):%s]"   <garagedoor> (Garden, Windows)                 ["GarageDoor"]

image

  • multiple properties for a single item was a little harder to grasp at first but I think in some cases it might make sense too, for example "water"+"pressure", "gas"+"pressure", "electricity"+"current" etc.

I have done the implementations in kaikreuzer#17 to play with the idea, but am happy to discuss it further.

@kaikreuzer
Copy link
Contributor Author

users would also want to query specific classes of equipments, like "show me all the doors"

"classes of" are exactly the words we define in the ontology. We define that there is such a concept as a "door" and we have some semantics attached to it. But this is the strict list defined in ESH - and (at least currently) not meant to be customized/extended by the user.
So what the user might want to do here is to create individual groups of things, like "all my roombas". I wouldn't know how to tag such a group item, though. Maybe we need an explicit "group of type" tag (which could also solve the fuctional groups such as "Lights", "Windows", etc. that we discussed above?).

I think rather than enforcing an 1 Brick entity <=> 1 ESH item principle, items should be allowed to have multiple "traits" i.e. carry multiple types.

I have also given it some thought and I fear that it will actually break the overall concept pretty much. The "semantics" metadata is supposed to cleanly identify what the item is about - note that the main point of Brick are their TagSets with which they try to express the full semantics in a single (multi segment) string, not requiring consumers (i.e. UIs, algorithms, etc.) to have intrinsic knowledge on what tags might be valid in which case and how to get some meaning from seeing multiple of them.
So my goal with the metadata provider was to do the complex job on the server and present the aggregated result in the metadata. Having multiple types (eq+point) on a single item would not fit for this.
Let me also briefly respond to your "pro" arguments:

Nothing prevents users from applying the tags they want to their items, even if they might be incompatible

We'll definitely need some validation, which should inform the user if he did any nonsense - when loading the files or maybe even already when editing them in VS Code. SO in short: Imho there should be something that prevents the user from applying "any" tag to any item.

It prevents the need for useless additional Groups with only one member and the need for "virtual equipments" and the like which might be difficult to understand

But if those setups evolve, you might get into all kinds of trouble: If you add a lock to the door, which you so far only used with a contact, you will be in the situation that a group item for the "door" is the only correct model and you'd have 2 point items assigned to it. If one of your items now already implicitly also is the equipment, you could not evolve your model in a correct way.

if you consider items with multiple types/properties to be an opaque group of Brick entities related to each other

I wouldn't call it opaque but rather "fuzzy" as you cannot get a clear statement from the semantics metadata on what that item represents as explained above. And note that items (with the exception of the group items) are ALL supposed to be point types as they should represent functionality.

Your "door" example actually shows this: As long as you only have contacts on them, the result looks all fine. But now imagine that you have contacts, locks, intrusion sensors etc. for your doors: You would not want to see this all as a flat list, but grouped by the individual doors.

for example "water"+"pressure", "gas"+"pressure", "electricity"+"current"

This is actually rather a "pro" argument for one of my initial questions above: "I wonder whether "Property" should be split into "Property" and "Resource""...

All in all, I would prefer not to merge kaikreuzer#17 now, but to rather stay with constraints in our model, but keeping it clean at the same time.

What I could imagine is that we find some middle way (more or less the virtual equipment idea from above): Already now, the tags, groups etc. is the "internal" information that is then aggregated to become the semantics metadata. So I am fine with allowing to add an equipment type tag to an item with a point type tag, which would make the metadata provider implicitly create an "virual equipment id", which cannot be retrieved through the REST API (as it is neither an item nor a thing), but which could be internally used to answer queries for points that are part of a specific equipment type - isn't that the main feature, we would need?

@ghys
Copy link
Contributor

ghys commented Oct 7, 2018

the main point of Brick are their TagSets with which they try to express the full semantics in a single (multi segment) string, not requiring consumers (i.e. UIs, algorithms, etc.) to have intrinsic knowledge on what tags might be valid in which case and how to get some meaning from seeing multiple of them.
So my goal with the metadata provider was to do the complex job on the server and present the aggregated result in the metadata

Ah, right. My view was the former, not the latter i.e. letting users annotate their items without getting in the way with validation etc. (which is imho more in line with the general philosophy of tagging), and have the metadata reflect these and augment them with additional info like relations, but not necessarily try to derive any kind of ultimate meaning - that would be up to the user, and sometimes it might even not make sense, but that'd be the user's responsibility, not the framework's. But now I see your point.

I wouldn't call it opaque but rather "fuzzy" as you cannot get a clear statement from the semantics metadata on what that item represents as explained above.

To be fair, in the door/contact sensor case above, it is kind of fuzzy :) - whether the OpenState is a point of the contact sensor or the door itself is debatable.

Your "door" example actually shows this: As long as you only have contacts on them, the result looks all fine. But now imagine that you have contacts, locks, intrusion sensors etc. for your doors: You would not want to see this all as a flat list, but grouped by the individual doors.

Of course, I think it's easily understood that in this model, the items are self-contained if they are not broken into a group hierarchy - if you apply the "Door" tag separately to several items, it's pretty clear that we're referring to different doors. If you have multiple equipments or points on the same door, then a group is naturally the only way to go.
One of the major goals with this idea was to let users express their semantics as concisely as possible and not hindering adoption in existing item models by being too much of a hassle - i.e. they won't bother creating a group unless they have at least 2 items to put in it.

Maybe we need an explicit "group of type" tag (which could also solve the functional groups such as "Lights", "Windows", etc. that we discussed above?).

Interesting idea! but I don't know how to express this cleanly either.

NB - A little off-topic, on a practical level, it would be great if this could be part of an openHAB distro build before Oct 21 ;)

@kaikreuzer
Copy link
Contributor Author

whether the OpenState is a point of the contact sensor or the door itself is debatable.

Yes, absolutely! My take would be that the functional assignment should always have the priority, so it would be a point of the door. If the same sensor has a "lowBat" channel/item, this would in contrast be a point of the contact sensor.

on a practical level, it would be great if this could be part of an openHAB distro build before Oct 21 ;)

Yeah, that's why I am trying to keep extended requirements out of this PR for now and rather see, what we still manage to push after an initial version is out.
@htreu wanted to finish his review last week, so I'd hope that it is merged very soon and I'll then push this out to openHAB asap. Note that I'd also like to have HABot being moved to openHAB and being part of the distro by Oct 21 as well!

@ghys
Copy link
Contributor

ghys commented Oct 8, 2018

Yes, absolutely! My take would be that the functional assignment should always have the priority, so it would be a point of the door. If the same sensor has a "lowBat" channel/item, this would in contrast be a point of the contact sensor.

It might actually be a point of both depending on the context... imho it should appear both "all my sensors" and "all my doors" queries as pictured above. For the "battery" point there is no debate indeed.
So if I have this right, it could eventually be modelled like this (supposing there is a way to specify both a Point and an Equipment, how it translates to metadata is still tbd);

Group gFrontDoorSensor                            ["Equipment_Sensor"]
Contact FrontDoor_Open         (gFrontDoorSensor) ["Equipment_Door", "Point_OpenState"]
Number FrontDoorSensor_Battery (gFrontDoorSensor) ["Equipment_Battery", "Point_BatteryLevel"]

Yeah, that's why I am trying to keep extended requirements out of this PR for now and rather see, what we still manage to push after an initial version is out. [...] Note that I'd also like to have HABot being moved to openHAB and being part of the distro by Oct 21 as well!

Okay - I'd still like the first version to be as useable as possible (close to the current version), to me it implies:

  • resolving the collision in types "Equipment_Sensor", "Point_Sensor" => maybe rename "Point_Sensor" to "Point_Measurement"?
  • making sure there's no collisions in synonyms (e.g. "Lights" appears in "Equipment_Lightbulb" and "Property_Light")
  • completing the synonyms in EN, DE & FR for all tags (from HABot's "tagattributes" property files)
  • extending the library with some common missing tags, and build more hierarchies for illustration purposes (those are suggestions and could be part of this PR or a subsequent PR if this one gets merged soon):
    • add "Radiator", "Fan", "AirConditioning", "Thermostat" below "Equipment_HVAC" (at some point there will probably be a need to reintroduce purpose tags i.e. "heating", "cooling", but for now they could be synonyms of a closely related equipment type)
    • add "Dishwasher", "WashingMachine", "Dryer", "Refrigerator" below "Equipment_Whitegood"
    • add "TV" below "Equipment_Screen"
    • add "Server", "Bridge", "Router", "Gateway" below "Equipment_NetworkAppliance"
    • add "SolarPanel", "Cistern", "Pump" to equipments
    • add "Office" (or "Study"), "DiningRoom", "DressingRoom", "Restroom" to locations
    • add "Brightness" to properties (maybe under "Property_Light"?)

@htreu
Copy link
Contributor

htreu commented Oct 8, 2018

@ghys I suggest to get this merged asap and you provide small follow up PRs containing your most urgent changes & enhancements.

@maggu2810 please have a look here since this stuff exceptionally has a deadline and Kai & me are already involved. Thanks :-)

Copy link
Contributor

@htreu htreu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My main comment is about the generated resource bundles and classes, which imho should not be included in the repo but be created during build time (just like the DSL models). Can be discussed/changed later.

Apart from that: LGTM.

@kaikreuzer
Copy link
Contributor Author

@htreu I approve your changes (thanks for them), but you they broke the build, so please also fix the build.properties.


RELATIONS_PROPERTY.put(Arrays.asList(Point.class), "relatesTo");
}
private final Map<List<Class<? extends Tag>>, String> RELATIONS_PARENT = new HashMap<>();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where's the benefit to have this really very static information in fields? If it is about making sure to have clean maps, shouldn't you maybe also clear the maps upon deactivation?
When changing it to fields, you should not use capitalised names anymore.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have to admit, I did this in the light of our recommendation to not have loggers defined static. I just realised that this is a recommendation from SLF4J where they say

instance variables are IOC-friendly whereas static variables are not

w/o any further explanation.

I guess static would be equally okay now.

shouldn't you maybe also clear the maps upon deactivation

I don't think so as the service instance will be disposed and garbage collected anyhow (thats at least my understanding). Initialising in activate was mainly done due to the lack of a constructor.

When changing it to fields, you should not use capitalised names anymore.

true, will change that.

@kaikreuzer
Copy link
Contributor Author

It might actually be a point of both

As I said, I would want to avoid this for now as it completely breaks the model. The "isPointOf" is a 1-1 relation and we should stick to it. Your example should thus not have an equipment tag, if the item is already a member of an equipment group item.

resolving the collision in types "Equipment_Sensor", "Point_Sensor"

In our ESH Wiki, we had called the point "measurement" instead of "sensor" (which is the term used in Brick). Shall I change it back to "measurement" and we accept to use a different vocabulary than brick (@gtfierro feel free to join the discussion, if you have any strong arguments against it)?

making sure there's no collisions in synonyms

That'll probably VERY hard... Do we really strictly have to avoid them or could a synonym be considered to be not-unique?

completing the synonyms in EN, DE & FR for all tags (from HABot's "tagattributes" property files)

Would be cool if you could do that as a follow-up PR!

extending the library with some common missing tags

Good suggestions. I'm fine with most of them and would suggest I think about it and do a follow-up PR once this here is merged.

@ghys
Copy link
Contributor

ghys commented Oct 9, 2018

As I said, I would want to avoid this for now as it completely breaks the model.

Sure, the model is already fine as it is and I won't question it anymore, but it's still important to challenge it with some anticipated real-world scenarios, as we should probably expect some confusion at first about how to tag items (notably Equipments & Points) and there will a need for coherent explanations and examples.

Shall I change it back to "measurement" and we accept to use a different vocabulary than brick

Do we really strictly have to avoid them or could a synonym be considered to be not-unique?

The problem is that the result of SemanticTags::getByLabelOrSynonym or SemanticTags::getById (with short form IDs) will not always be predictable i.e. getById("Sensor") or SemanticTags::getByLabelOrSynonym("lights") while deterministic won't necessary return the expected tag. I run into it immediately while querying for "lights" and it found nothing because it resolved it as Equipment_Lightbulb and I tagged the items with Property_Light. Maybe those methods could return a collection of all matching tags for a given id, label or synonym, then collisions would be acceptable.

would suggest I think about it and do a follow-up PR once this here is merged.

Would be cool if you could do that as a follow-up PR!

Will do the PR with the synonyms and translations, but maybe it's better to wait for the ontology to be stabilized first then.

@kaikreuzer
Copy link
Contributor Author

but it's still important to challenge it with some anticipated real-world scenarios

Yes and I'd hope we can involve @gtfierro in that discussion as well as he analysed many real-world cases when designing Brick - so he might have worthwhile input on that.

Maybe those methods could return a collection of all matching tags for a given id, label or synonym, then collisions would be acceptable.

Yeah, this is probably the best solution.

Will do the PR with the synonyms and translations, but maybe it's better to wait for the ontology to be stabilized first then.

Agreed, I'll work on the PR for the ontology amendments tonight.

@kaikreuzer
Copy link
Contributor Author

Agreed, I'll work on the PR for the ontology amendments tonight.

I've just pushed a (small) change - point sensor is now point measurement and point command is point control (i.e. I reverted to our own vocabulary on these).

I contemplated over the ontology additions for an hour and eventually came to the conclusion that they should not be introduced so quickly. Most of them do not seem to deliver real semantical value for our use cases, which would differ from any tag that is already defined. The additions essentially boil down to a "common vocabulary", which would make it easier for people to define labels & synonyms for their items (because they would simply tag them accordingly). But if this is the major benefit, I still prefer to start small - people can still name their items "diswasher" or "tv" and they will be found. It is a bit more cumbersome to define for them, but it gives them the flexibility to call it by whatever name they want.
Note that Alexa&Co. usually started with only 3 device types and added further stuff over time. I'd have some comment for every single one suggestion of the list, but it would take too long to discuss it all here.

add "Brightness" to properties

Brightness should be the very default when talking about "control" & "llight" with switches or dimmers. The information that if the user wants to "adjust brightness" you need to "control light" should imho be part of HABot and not required to be stored in the ontology.

Maybe those methods could return a collection of all matching tags for a given id, label or synonym, then collisions would be acceptable.

I have changed the getByLabelOrSynonym method accordingly now.

@afuechsel
Copy link
Contributor

I'd like to ask to update the wiki page https://github.com/eclipse/smarthome/wiki/Semantic-Tag-Library whenever there are changes in the tag names so we could align properly. :)

@kaikreuzer
Copy link
Contributor Author

@afuechsel I'd plan to generate a documentation page out of the csv - we should not keep using the wiki on the long run.

Signed-off-by: Kai Kreuzer <kai@openhab.org>
@gtfierro
Copy link

Sorry for getting to this so late @kaikreuzer. I've been reading through this discussion to try and get a feel for the issue at hand, so please let me know if I'm misunderstanding it.

In Brick, we used the word Measurement to refer to the quantity that was being measured, and used Sensor (which was a subclass of the broader Point class) to refer to the actual entity performing the measurement.


As to your request for real-world scenarios, I would start with annotating some common equipment and simple building structures. What does a Thermostat look like under the scheme, and what kinds of relationships/annotations would you want to capture? For a thermostat, this might look like

Thermostat

    Points:
    - heating temperature setpoint (F)
    - cooling temperature setpoint (F)
    - state (heat-stage-1/cool-stage-1/heat-stage-2/cool-stage-2/off)
    - mode (heat-only/cool-only/auto/off)
    - temperature (F)
    - relative humidity (% rH)

    Relationships:
    - Rooftop Unit being controlled
    - room thermostat is located in
    - list of rooms that the thermostat conditions

    Metadata:
    - make/model of thermostat

Then you could go on to model simple structures and expand them outwards to capture more of the system, such as a thermostat, the room its in, the RTU it controls, the rooms that are conditioned by the RTU, the electric meter upstream of the RTU, which floor the room is on, etc...

Depending on the scope of the ontology, you might find it helpful to go through some of the buildings that we created Brick models for. You can look at the viewer.brickschema.org site to get a sense for how Brick models are laid out. I could give you a big CSV of all the points/equipment in those buildings, if you'd like.

@htreu htreu merged commit 842d34a into eclipse-archived:master Oct 11, 2018
@kaikreuzer
Copy link
Contributor Author

kaikreuzer commented Oct 12, 2018

Hey @gtfierro, thanks for your feedback!

we used the word Measurement to refer to the quantity that was being measured

I'd think Quantity would be a better name for the reference to the quantity ;-)

and used Sensor (which was a subclass of the broader Point class) to refer to the actual entity performing the measurement.

And it is defined as a "Device or instrument designed to detect and measure a variable." - to me, this sounds much more like an Equipment (i.e. the real hardware and not some function/point) and thus we also have a "Sensor" as an Equipment in our ontology.

For a thermostat, this might look like

The points look straight forward, but how would the relations exactly be modelled?

  • "Rooftop Unit being controlled" -> Is this a "thermostat feeds rooftop unit"?
  • "list of rooms that the thermostat conditions" Is this a "thermostat feeds room X"?

If so, our problem might be that we do not use the "feeds" relation at all. I do not really fully get the its purpose and I am not sure that it can solve our problem.

Just to summarise the main question again:
If we have a Point "Window_Sensor", how do we express that it is a) a Point of our Equipment "Magnetic Contact Sensor Device" (or however that might be called) and at the same time b) a Point of the "Window" Equipment?

Would it simply mean that the Point is a "point of" both those equipments (i.e. the sensor device and the window)? We so far have it as a 1:1 relation, not a 1:n - so maybe we need to change this?

Btw, I see that the BrickFrame.ttl defines many relations and also in a very generic (i.e. little constrained) way - it hardly reflects the diagram in the leaflet:

screenshot 2018-10-12 at 18 16 20

Should this be considered to be outdated (it does not even allow Points being "point of" an Equipment)? Is there anywhere a more recent version of these relations diagram?

ghys added a commit to openhab/org.openhab.ui.habot that referenced this pull request Oct 14, 2018
BREAKING: Requires an openHAB distribution including openhab/openhab-core#415 to work!
Related to eclipse-archived/smarthome#6288. Requires compatible tags.

Extract name samples from tags, item labels & synonyms (comma-separated strings in the "synonyms" metadata namespace)

Other misc changes:

* Fix location dropdown counters in card deck
* Fix invisible send button in chat text field
* Better title & subtitle in generated chart cards
* Expand matched groups automatically
* Fail most skills if no entities found

Signed-off-by: Yannick Schaus <habpanel@schaus.net>
@gtfierro
Copy link

The Brick relationships diagram is a little out of date, but is still mostly true. It has elided the implicit "reverse" relationships for simplicity. Equipment can hasPoint a Point, which implies that Point can isPointOf an Equipment; the reverse relationships are defined in the BrickFrame.ttl file. These restrictions should be expressed in that file, so I'm surprised to hear if they're not there. The relationships are heavily used across Brick

We haven't kept any of the relationships at a strict 1:1, specifically for these cases where you could make the case that a Point is associated with multiple other entities: equipment, locations or other points. What is a Window_Sensor in this case? In Brick a Point is essentially a timeseries -- a sensing/actuation point -- that's decoupled from the physical device performing the measurement. Under this, I think it makes sense that a Point could have a 1:n isPointOf relationship with multiple other entities.


For the case of the thermostat, we'd do "Rooftop Unit being controlled" as

bldg:tstat    a    brick:Thermostat .
bldg:rtu       a    brick:Rooftop_Unit .
bldg:tstat    bf:controls   bldg:rtu

and then model the relationship from the thermostat to the rooms by going through the RTU to the HVAC Zone

bldg:zone    a    brick:HVAC_Zone .
bldg:room1    a    brick:Room .
bldg:room2    a    brick:Room .
bldg:zone     bf:hasPart     bldg:room1 .
bldg:zone     bf:hasPart     bldg:room2 .
bldg:rtu        bf:feeds      bldg:zone .

@kaikreuzer
Copy link
Contributor Author

Thanks @gtfierro, makes all sense.
The interesting part would now be if you could add the Points in your thermostat example above as well - like a

bldg:room1Temperature a brick:Sensor ,
bldg:zoneSetpoint     a brick:Setpoint

What relations would those have?

And another question: Is the "feeds" relation defined in detail somewhere? Its meaning appears to be clear for physical stuff like air and water, but is it only applicable for those? Or is its meaning more generally something like "performs its function in" or "has an effect in"? What e.g. about a switch actuator that is located in a different room than the light that it switches? Would that "feed" the room with light?

@gtfierro
Copy link

Assuming that they're associated with the thermostat, then we would do

bldg:tstat    a    brick:Thermostat .
bldg:room1Temperature a brick:Sensor 
bldg:zoneSetpoint     a brick:Setpoint
bldg:tstat    bf:hasPoint    bldg:room1Temperature .
bldg:tstat    bf:hasPoint    bldg:zoneSetpoint .
bldg:tstat    bf:hasLocation    bldg:room1

The last triple places the thermostat in the room so that you can query the model for points of equipment in a room. Its important to capture this relationship because the thermostat isn't always in one of the rooms in the HVAC zone.


I don't know if feeds is described "in detail" :) but it has to do with the flow of some physical media. In the cases you mentioned, the Luminaire would "feed" a room with light. The switch would have a "controls" relationship with the Luminaire. Similarly, a thermostat has a "controls" relationship with the RTU, which has a "feed" relationship (of conditioned air) to an HVAC zone.

@htreu htreu added this to the 0.10.0 milestone Oct 30, 2018
@openhab-bot
Copy link
Contributor

This pull request has been mentioned on openHAB Community. There might be relevant details there:

https://community.openhab.org/t/semantics-and-metadata-for-alexa-skill/66436/1

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

Successfully merging this pull request may close these issues.

6 participants