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

Create static constants for the default semantic tags #4622

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

jimtng
Copy link
Contributor

@jimtng jimtng commented Feb 26, 2025

This enables the default semantic tags to be referred to as constants by bindings to enable compile time check.

@jimtng jimtng requested a review from a team as a code owner February 26, 2025 13:44
@jimtng
Copy link
Contributor Author

jimtng commented Feb 26, 2025

@andrewfg you might be able to use this

@jimtng jimtng force-pushed the static-semantic-tags branch from 5b02a6a to d008c2f Compare February 26, 2025 22:36
@jimtng
Copy link
Contributor Author

jimtng commented Feb 27, 2025

If we can be sure that the "simple" tag names must be unique, we can simplify the constants to just the last part of it, i.e.

CAMERA instead of EQUIPMENT_CAMERA.

Signed-off-by: Jimmy Tanagra <[email protected]>
@andrewfg
Copy link
Contributor

andrewfg commented Feb 27, 2025

Umm. Actually I strongly prefer the constants WITH prefixes. When developing a binding, if you want to apply a tag on a thing then the tag must be an EQUIPMENT_xx tag. Or if you want to apply tags to a channel they must be POINT_xx and/or PROPERTY_xx tags.

@andrewfg
Copy link
Contributor

@jimtng here is an example piece of code from the Hue thing handler whereby the thing's semantic equipment tag gets set dynamically. Ideally I would pull in your EQUIPMENT_xx tags from this PR rather than using hand coded strings.

    /**
     * Update the thing's semantic equipment tag. The main determinant for the equipment type is the supported channels.
     * For lights use the product archetype to split between light bulbs and strip lights. Rooms and Zones are
     * considered to be (groups of) light bulbs.
     */
    // TODO use the semantic tag constants from OH core
    private void updateSemanticEquipmentTag() {
        String semanticEquipmentTag = null;

        // sensor equipment
        if (supportedChannelIdSet.contains(CHANNEL_2_LIGHT_LEVEL) //
                || supportedChannelIdSet.contains(CHANNEL_2_MOTION)
                || supportedChannelIdSet.contains(CHANNEL_2_TEMPERATURE)) {
            semanticEquipmentTag = "Sensor";
        } else

        // security equipment
        if (supportedChannelIdSet.contains(CHANNEL_2_SECURITY_CONTACT)) {
            semanticEquipmentTag = "Security";
        } else

        // button equipment
        if (supportedChannelIdSet.contains(CHANNEL_2_BUTTON_LAST_EVENT)) {
            semanticEquipmentTag = "Button";
        } else

        // rotary dial equipment
        if (supportedChannelIdSet.contains(CHANNEL_2_ROTARY_STEPS)) {
            semanticEquipmentTag = "RotaryDial";
        } else

        // rooms and zones are a super-set of light bulb equipment
        if (thisResource.getType() != ResourceType.DEVICE) {
            semanticEquipmentTag = "LightBulb";
        } else

        // everything else is individual light equipment
        if (thisResource.getProductData() instanceof ProductData productData) {
            if (STRIPLIGHT_ARCHETYPES.contains(productData.getProductArchetype())) {
                semanticEquipmentTag = "LightStrip";
            } else {
                semanticEquipmentTag = "LightBulb";
            }
        }

        logger.debug("{} -> updateSemanticEquipmentTag({})", resourceId, semanticEquipmentTag);
        updateThing(editThing().withSemanticEquipmentTag(semanticEquipmentTag).build());
    }

@jimtng
Copy link
Contributor Author

jimtng commented Feb 28, 2025

Actually I strongly prefer the constants WITH prefixes. When developing a binding, if you want to apply a tag on a thing then the tag must be an EQUIPMENT_xx tag. Or if you want to apply tags to a channel they must be POINT_xx and/or PROPERTY_xx tags.

I believe that I understand your point.

My thinking is that when you're setting a tag here, you are selecting the "end point" of the tag without dictating the exact hierarchy of the tag. Yes, it must be a certain type (Equipment vs Point / Property) but in here you are not dictating that Equipment Z must be a subcategory of Y which is the subcategory of X.

So instead of stating here DefaultSemanticTags.EQUIPMENT_X_Y_Z, you just say DefaultSemanticTags.Z.

This frees up the ability later on to restructure Z within core to be either promoted or demoted e.g. to become EQUIPMENT_Z, EQUIPMENT_X_Z, or even EQUIPMENT_A_B_Z without having to make changes in all the consumer of the constants.

It is still Z to you here, due to the virtue of Z having to be unique. There can never be EQUIPMENT_A_Z and EQUIPMENT_B_Z to require specifying the full path.

The advantage is simpler looking code. You know you want a FRIDGE. You shouldn't have to care if it's EQUIPMENT_FREEZER or EQUIPMENT_WHITEGOODS_FREEZER, or anything else.

It has a 1 to 1 equivalent of using a plain string vs constant.

A possible compromise could be to create the constants as TYPE_ENDNAME without having the hierarchy. So we'll have

EQUIPMENT (the root tag)
EQUIPMENT_FREEZER (not EQUIPMENT_WHITEGOODS_FREEZER)
LOCATION_LAUNDRYROOM (not LOCATION_INDOOR_ROOM_LAUNDRYROOM)

However this has the potential to be confusing.

Signed-off-by: Jimmy Tanagra <[email protected]>
@jimtng
Copy link
Contributor Author

jimtng commented Feb 28, 2025

A possible compromise could be to create the constants as TYPE_ENDNAME without having the hierarchy. So we'll have

EQUIPMENT (the root tag) EQUIPMENT_FREEZER (not EQUIPMENT_WHITEGOODS_FREEZER) LOCATION_LAUNDRYROOM (not LOCATION_INDOOR_ROOM_LAUNDRYROOM)

I've changed it to this scheme now. I recognise that this makes it very clear the type of the tag without getting into the hierarchy details.

defaultTags.add(DefaultSemanticTags.LOCATION_GARAGE);
defaultTags.add(DefaultSemanticTags.LOCATION_HOUSE);
defaultTags.add(DefaultSemanticTags.LOCATION_SHED);
defaultTags.add(DefaultSemanticTags.LOCATION_SUMMERHOUSE);
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe we could use the casing ("SummerHouse") to also separate words with underscore, so this would become LOCATION_SUMMER_HOUSE, WDYT?

@andrewfg
Copy link
Contributor

create the constants as TYPE_ENDNAME without having the hierarchy

Exactly. That is all I am asking for.

The idea of tag nesting is too complex to automate anyway.

Another (much better) idea would be to put the different classes of tag constants into actually different java classes. So you would have four classes Equipment, Point, Property, Location that contain each their own tag constants. So instead of using EQUIPMENT_XXX one would use Equipment.XXX

@jimtng
Copy link
Contributor Author

jimtng commented Feb 28, 2025

@andrewfg and @jlaur - updated to
DefaultSemanticTags.Location.SUMMER_HOUSE

Copy link
Contributor

@andrewfg andrewfg left a comment

Choose a reason for hiding this comment

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

LGTM subject to #4616 and #4619 being merged.


EDIT: actually we don't need to wait for those PRs as their content can be added later I think. Or??

@@ -60,6 +64,62 @@ def appendLabelsFile(FileWriter file, def line, String tagSet) {
file.write("\n")
}

def camelToUpperCasedSnake(def tag) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Brilliant! One of my wishes (when I grow up) is to be able to do regexes like that..

* @author Generated from generateTagClasses.groovy - Initial contribution
*/
@NonNullByDefault
public class DefaultSemanticTags {
Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, I like this structure. Thankyou.

Signed-off-by: Jimmy Tanagra <[email protected]>
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

Successfully merging this pull request may close these issues.

3 participants