YAGSA - Yet Another Group Structure Approach


(Thomas Bail) #1

Like others, I’m in the process of completely reworking my openHAb installation and organizing it a little bit differently. One of the tasks in the reorganization is the restructuring of the groups. I have given some thought to this and would like to hear your opinion.

Here’s the result of my deliberations::

Thing Groups
Different items belong to a thing and are grouped together in a corresponding thing group. All items belonging to a thing can be easily displayed in a Basic Sitemap for debugging. If there are only virtual items, i. e. without thing, a corresponding thing group is defined on the basis of the items, since there are usually several.

image

Group gGF_LR_MyThing "My Thing" <my_icon> (gMyLocation, gMyContext)
Item GF_LR_MyThing_State "My Thing State" <my_icon> (gGF_LR_MyThing, gOtherRequiredGroups)
Item GF_LR_MyThing_Battery "My Thing Battery" <my_icon> (gGF_LR_MyThing, gOtherRequiredGroups)
Item GF_LR_MyThing_Unreach "My Thing Unreach" <my_icon> (gGF_LR_MyThing, gOtherRequiredGroups)

Group Hierarchy
Groups are organized hierarchically starting from a root (gRoot - I don’t like gALL). There are three main structural groups:

  • Location-based groups (gLocation) in which the thing-groups are assigned according to their location
  • Context-related groups (gContext) in which the thing groups are assigned according to their main context
  • Persistence groups (gPersistence) in which items are assigned to different types of persistence

As with the Thing Groups, a simple mapping in a Basic Sitemap for debugging purposes is easy to implement. All items can be displayed in a structured way by embedding gRoot in a sitemap.

Location-related groups
The location-based groups should be self-explanatory. So typically the floors, rooms, etc… In my case, this is what it looks like:

Context-related groups
In addition to the location-related groups, there are context-related groups. In these groups, the thing groups are assigned to a group according to their main function. I have defined the following groups, but they can also be extended:

  • gIllumination - Everything related to lighting. Switches, socket outlet switches, lamps, LED strips,…
  • gSurveilence - Everything related to surveillance. Motion detectors, door and window contacts, cameras,…
  • gEnvironment - Everything related to environmental data. Temperature, Humidity, Weather data,…
  • gHeating - All things to do with heating; Thermostats, thermostats,…
  • gControl - Everything that basically has to do with the subject area of control and is not already arranged elsewhere. Washing machine control,…
  • gInformation - Everything related to information. Battery status, fuel prices,…
  • gMultimedia - Everything related to multimedia. TV, Sonsos,…

image

Persistence Groups
The third of the main groups is the persistence group, which controls persistence for individual items. For me I currently see two subgroups. Once persistence via a mapdb e. g. to perform a restore at startup and on the other hand the persistence for the influxdb with which nice graphics are made via Grafana.

image

Functional Groups
In addition to the groups, there are the functional groups (Switch, Contact,…) and dynamically filled groups. These are assigned to the corresponding context groups. For example, the functional group with the status of all batteries fgBatteries is assigned to the context groups gInformation or the cascaded lighting groups of the context group gIllumination.

Based on the statements made so far, each thinggroup has at least two group memberships (place and context). Each item has at least the assignment to the Thing Group and can have further group memberships such as functional or persistence groups.

In total, the whole thing looks like a mindmap as follows.

So much for my considerations. I would be happy to receive any additions and comments.

Thomas


InfluxDB+Grafana persistence and graphing
( ) #2

Hey Thomas,
interesting you are posting this thread now. Maybe you want to join the discussion surrounding this Pull Request for our documentation.


( ) #3

Going through your thread here are a few thoughts from myself:

  • Your basic strategy is pretty similar to mine, I like it.

  • Is there a special difference between “Context-related groups” and “Functional Groups”? For me these are the same. e.g. I have a group “gMaintenance” with a subgroup “gBattery”.

  • I disagree with the introduction of Persistence Groups. I don’t think it’s meaningful to mix Item definition and persistence definition if that can be avoided. It can. You’ve already defined “Functional Groups” which can in the next step be added to your persistence configuration. Clean, separate, error-resistant.

  • What’s your naming scheme? Please compare the PR suggestion.

Would be great if you could join the PR discussion and help make the PR a recommendation for everyone.


(Kjetil Asdal) #4

Very interesting post, and I must say, a well though through concept!

As many others, I guess, I have spent some time myself on coming up with a naming convention, but in my case only for items so far. Next on my list was groups, but I think I will pick-and-choose from this thread, :slight_smile:

The naming convention that I am using for items across my system - and that have not broken down so far - is as follows:

[<Where>_][<What>_]<Type><Property>[_<Attribute>]

Where:
    Living room, outside, etc.

What:
    Door, lamp, etc.

Type:
    a   - actuator (connected to a binding); both postUpdate and sendCommand are relevant.
    s   - sensor (connected to a binding); only postUpdate is relevant.
    t   - timer (connected to 'expire'-binding); is this needed/meaningful?
    v   - virtual (not connected to a binding; only modified by rules or UI); both postUpdate and sendCommand are relevant.

Property:
    Temperature, humidity, power, etc.    

Attribute:
    Last update, last change, etc.

Where, what, property and attribute are all "upper camel case" (ex. ThisIsAnExample). 

The “attribute” part is basically the same as described here: Design Pattern: Associated Items

Here are some examples:

LivingRoom_sTemperature
LivingRoom_Light_aDimmer
LivingRoom_TV_aPower

==

When it comes to groups, what I have considered so far is that I want to be able to describe my system in “three models”:

  1. Device-centric (i.e. things. This is mostly for debugging/maintenance)
  2. Location-centric (i.e. floors, rooms, garden, etc.)
  3. Function-centric (i.e. heating, lighting, etc.)

This matches very well what the original post describes.


( ) #5

Hey Kjetil you are also invited to join the PR discussion :wink:

May I ask about the importance of “Type” to you? I understand the idea behind this part and others have shown similar ideas in the past. Did you ever find it actually useful during e.g. rule development?


(Kjetil Asdal) #6

Excellent question! I think the type does carry some significance in that, when writing rule triggers, an a-type or v-type item may (if needed) trigger on “received command”, while an s-type item may only trigger on “received update” (or changed).

This kind of distinction was the rationale behind adding the type. I must admit that in practice, however, I find myself having the items file open - and looking at the details more than the type - when writing rules, :slight_smile:

I guess this means that I could skip the type from this perspective. It does serve another purpose, however, and that is marking the “point” between the Where/What part and the Property part of the item name and that makes it very easy to quickly identify the two different parts of the naming convention when reading item files.

I am very aware that for this purpose I should rather use some other concept, but since I have already “used up” the underscore character, that little “small cap”-letter has proven useful, :slight_smile:


(Rich Koshak) #7

See Group Based Persistence DP which Dibbler42 is applying here (I can tell by the group names :slight_smile: ).

I can see arguments both ways but I wrote up and implemented this DP because it feels like a violation of DRY, and a source for copy and paste errors and the like, to list each Item in the .persist file individually when I can effectively tag those Items I want persisted using a Group.

Also, I may not want everything in a given functional Group to be persisted. For example, I want to chart my house fan and heating’s ON/OFF state against the room temperatures. But I don’t want to chart ALL of the rest of the stuff that goes in the heating functional group. Similarly, I want to chart the outside temp and humidity I pull down from Wunderground but not everything I pull down from wunderground.

Pulling Persistence out as a separate Group gives me the ability to tag those Items I want persisted as I define the Items.

I does mix concerns slightly, but no more than defining the label and icon at the Item mixes concerns with the sitemap. And I don’t think it is any more or less prone to errors.

I don’t know if Kjetil took the idea from me or we came up with it independently but I’ll say from my usages it has come in helpful when dealing with situations where you have both a sensor and an actuator on the same Thing (whether actual OH 2.0 Thing or just logically a collection of Items that represent different aspects of the same device). For example, I have a Garage Door Opener with an actuator and a sensor. Using the Type lets me have:

Switch aGaragedoor1 // activates the opener
Contact vGaragedoor1 // indicates whether the door is open or closed

My overall naming scheme is very much like Kjeitil’s with some simplifications:

<Type><Name>[_<Attribute>]

Type:
    a:  actuator - sending a command causes something to happen
    v:  value    - represents a sensor value or stored state, always use postUpdate/receivedUpdate in the rules
    g:  group    - represents a Group, I'm considering dropping this and just applying the first two, or perhaps reserving
                   this only for those Groups I do not give a type to (and therefore do not receive updates nor can be 
                   commanded).

Name:
    Name of the Item, be as descriptive as necessary, use CamelCase

_Attribute:
    Optional, attribute used to more easily apply the Associated Items DP. The ones I use in my setup are:

    _Timer:       an Expire Binding based Timer associated with the Item whose name matches the first part of the name
    _ Lastupdate: a DateTime representing the last time the Item whose name matches the first part of the name changed state
    _Alerted:     a flag indicating that an alert has already been sent for the currently detected alerting state (e.g. if I send 
                  an alert that a door has been open for an hour, I don't want to keep sending that same alert every time the 
                  sensor for that door updates).
    _Heartbeat:   I may drop this one too at some point, represents an Item whose sole purpose is to get an update 
                  periodically to show something is online, my zwave smoke alarms, Arduino sensors, and 
                  sensorReporters send out heartbeats like these. I don't actually use these with Associated Items so  I don't
                  need this attribute.

In the rare cases where I care about where something is, I include it in the Name portion of the Item’s name. So far I’ve not had a need to distinguish between Items based on location and adding the location is just a way to give the Item a unique name (e.g. aFrontroomLight versus aFamilyroomLight).

I’m not married to putting the Type as the first letter (to address your dread of Hungarian notation @ThomDietrich :wink: ) but the main thing driving my naming convention is the Associated Items Design Pattern. No matter what I come up with it must be easy to parse and programatically create Item names that are associated with each other.

Now I am intrigued by @Dibbler42’s idea to Group Items from the same Thing together and would have to give this some thought so see if it will help me in some areas. Overall I prefer a relatively flat hierarchy so I don’t know if I would go that way but I’m always open to new ideas.

Finally @Dibbler42, I think this will count as a milestone in your growth as an OH user. I think all of us struggle with various aspects of our systems but eventually, we start to consider the overall design from a more abstract meta perspective. Postings like this show you are seriously thinking about your design in a systematic way, not just how to make things work.

Congratulations! In my book that puts you at the Master OH User Level! :mage:

Don’t get too proud, even the Masters have a ton left to learn. :slight_smile:


(Thomas Bail) #8

Gentlemen,

Thank you very much for your feedback. I’ll try to go into the individual topics.

@ThomDietrich
As soon as I find the time, I’ll check the pull request. Until then feel free to use any of my ideas if it is useful for the discussion. An interesting point of view is to see the groups as dimensions. I think it fits very nicely.

Yes, there is a big difference between context and functionalin my point of view. The context groups are essentially the same as your logical groups, i. e. they only combine items or other groups. Functional groups have a switch or contact or … function which is not available in the “normal” groups. Example:

Group:Switch:OR (ON, OFF) gChristmasTreeSwitches "Weihnachtsbaum ist ..." <light_xmas_tree> 

I can’t follow you on the persistence groups. These have nothing to do with the functional groups. Here is my persistence configuration and the matching group and a matching item. Maybe that closes the gap in our understanding.

Strategies {
	default=everyUpdate
}

Items {
	gChart*	: strategy = everyUpdate
}
Group gPersistence "Historisches, Status und Startup" <edit_settings> (gRoot)
	Group gChart "Timeline Items" <time_graph> (gPersistence)

Group gInformation "Informationsgruppen" <edit_settings> (gRoot)
	Group:Switch:OR(ON, OFF) fgBatteries "Status aller Batterien [%d]" <measure_battery_0> (gInformation )

Group gGF_VR_Thermometer "Thermometer Veranda" <temp_outside> (gGf_Veranda)
Number GF_VR_Thermometer_Temperature "Temperatur Veranda [%.1f°C]" <temp_outside> (gGF_VR_Thermometer, gChart)
Switch GF_VR_Thermometer_LowBattery "Thermometer Veranda" <measure_battery> (gGF_VR_Thermometer, fgBatteries)

As you can see, only the temperature is persisted for charts. So I only assign the group and don’t have to change the persistence configuration. The functional group fgBatteries combines all batteries together

And now to the naming scheme, with which I am not 100% happy.

Items
_

Area and Room are abbreviations with 2 characters each, which is a TradeOff between length and readability for me. If you are interested, I will also post the abbreviations I have defined.

@KjetilA
A nice scheme. I used to have the type too, but I threw it out again. Property is the channel for me and I haven’t thought about the attribute yet. Until I’m really clear with the names, I have to study the great design patterns from rich

@rlkoshak
Thank you for the knighthood :slight_smile:
Your persistence representation fits into my world of thoughts and I have to take a closer look at the topic of attribute.


( ) #9

Hey Thomas,

happy to see your thoughts over in the PR.

It’s quite easy. I believe (and made the experience) that it’s quite annoying to add persistence configuration to the items definition… isn’t there a better place!? Ah right, the persistence configuration :smiley:
Maybe my configuration will explain it better: https://github.com/ThomDietrich/openhab-config/blob/master/persistence/influxdb.persist
I could modify or delete the file, create a second for another persistence service or adapt strategy settings. All of that without touching my items and mixing different parts of my configuration.


(Rich Koshak) #10

I can do all of that with the Group Based Persistence Approach too. I define persistence Groups based on the type of persistence I want to have available:

  • gRestoreOnStartup (I restore everything so I don’t actually use this group but if you are selective on what you want to restore you would create such a Group) - Items to restoreOnStartup
  • gChart - Items I want to graph
    -gHistory - Items I want historic data about in my Rules but don’t want to chart

For the above I would use three different persistence engines:

  • gRestoreOnStartup -> MapDB
  • gChart -> InfluxDB
  • gHistory -> rrd4j

As I create my Items I add them to the Group or Groups as appropriate. If I change my mind I remove them from the Group.

If I decide I want to drop rrj4j entirely (which I have BTW) I delete my rrd4j.persist file and add gHistory to my influxdb.persist file. If I decided to use MariaDB instead of InfluxDB for some odd reason, I just delete influxdb and add gChart and gHistory to mariadb.persist. If I want to do both maria and influxdb I add both groups to both files. In none of these cases are the Items touched.

The Groups define WHY I want to persist the Item. What that means (i.e. which database gets used, how frequently, etc.) all gets defined in the .persist file.

For example, in influxdb I have everyChange for gChart. Based on our conversation on another thread, I will probably change that to everyChange and everyHour to make Grafana happier. That is no more or less work than your approach. If I want to go back to rrd4j for charting I just copy over gChart to rrd4j.persist and make sure it has an everyChange,everyMinute strategy.

I can see one circumstance where listing everything in your .persist files has an advantage over Group Based Persistence: if you spend more time tweaking your persistence than creating new Items.

I spend far more time creating and modifying Items than monkeying with my persistence so with my work pattern it is far less annoying to tag an Item with a Group to get it persisted then it is to update the .persist file all the time.

Beyond that distinction, it’s mox nix in my book.

I understand the desire not to mix different parts of your configuration, but that argument carries less weight for me when you define your label and icons in your .items files. You are already mixing parts of the configuration (in this case mixing your data model with your view).


(Thomas Bail) #11

You droped the rrd4j did that mean you dropped the gHistory too or i gHistory now on influx too and what happens if we define the same item with two time the same persistence or ist you strategy different for chart and history?


(Rich Koshak) #12

I put gHistory into InfluxDB for now. I really only have a couple of Items that are in gHistory that are not already in gChart.

That is a good question. I am pretty sure, though haven’t verified, that if the same Item is a member of both groups, it will get saved only once. But that would need to be verified. For the most part I only use the most recent historical value so I’ve never had to do anything that might reveal there is a problem.


(Mark Webster) #13

Hi All

I’m hoping for a bit of advice of the use of groups… I’ve setup a hierarchical group structure along the lines of the original post in this thread, but this has thrown up some questions for me on using these groups in rules.

As I understand, the way groups need to be defined in order for groups to be updated when group members are updated has changed and now the groups need to be defined with a Type as well. Can someone explain how this impacts on using these groups to trigger rules when the items contained within the groups may well be of different Types?

Thanks


(Rich Koshak) #14

I’ve not tested it but I believe that if as long as the group has a type it will receive updates when a member changes. But it’s an easy thing to test with the groups you have now.


( ) #15

Hey Mark,
just a reminder. Since the tutorial here was written we have also updated the documentation, partly including ideas discussed here. You might find further answers there:

http://docs.openhab.org/configuration/items.html#name
http://docs.openhab.org/configuration/items.html#groups
http://docs.openhab.org/configuration/items.html#group-type

I believe we have answered most of your questions in the latest update. If not this would be a good moment to figure out what is still missing.


(Mark Webster) #16

Hi

Thanks for the info… All makes sense to me when a group has multiple items of the same type such as all Switch which will all have a state of ON or OFF or all Contact which will all have a state of OPEN or CLOSED, but what about a group that has both Switch and Contact items? How will the state of the group then be recorded? What Type should the group then be defined as?


(Michael Cumming) #17

I am wondering how people are locating stairways. Ie. where do they belong on the location scheme - do you assign them to one floor/level? Or do you have a strairs up and stairs down group for floors with both?

Mike


(Thomas Bail) #18

I assign them to a floor level. Becaus i have only one stair from gound to furst floor ist is assigned to the groundfloor. Every schene has its problem


(Michael Cumming) #19

Thomas, that’s what I am planning on doing, Starting at the basement and working my way up. Thanks, Mike


(Michael) #20

Hi Dibbler42,

did you draw these nice pictures manually or is there a script that creates these dependency graphs automatically?

I would like to have an easy way to get an overview for my own groups. And before I write that script myself … it’s worth asking.

Thanks.