From 272d186254d85d939de8b0cbb9e1c6ee0757e75a Mon Sep 17 00:00:00 2001 From: Yannick Schaus Date: Sat, 16 Jun 2018 01:10:25 +0200 Subject: [PATCH] Transition to metadata & semantic tags understanding This introduces BREAKING CHANGES! Following the discussion in https://github.com/eclipse/smarthome/issues/1093 the mechanism matching the entities extracted by OpenNLP from the natural language query to ESH items is being altered in this way: 1. Tags are not the primary conduit for item identification: this change introduces the concept of "Named Attributes" which will be implicitely affixed to items by a new class/ OSGi component, the `ItemNamedAttributesResolver` 2. Tags are now expected to conform to a semantic tag library: the current version is at https://github.com/eclipse/smarthome/wiki/Semantic-Tag-Library HABot has internal translations for the most useful semantic tags in the languages it understands and will derive named attributes for items from those `tagattributes_{locale].properties` resource bundles 3. In addition to tags, users may specify additional "monikers" for items by using metadata in the "habot" namespace: ``` Group FF_ChildsRoom { habot="Amy's room" [type="location"] } ``` Those monikers will also be added to item's named attributes set. The "type" configuration property is optional: if left unspecified, monikers will have the "object" type. 4. Inheritance is still assumed for applied tags and monikers specified in metadata for Group items, EXCEPT if the inheritTags configuration property in the "habot" metadata namespace prevents it (for tags only, metadata monikers are always inherited), like so: ``` Group Kitchen ["object:room"] { habot="Cuisine" [ inheritTags=false ] } ``` 5. "habot:" prefixed tags will move gradually to the "habot" item metadata namespace. Signed-off-by: Yannick Schaus --- .../openhab/ui/habot/card/CardBuilder.java | 31 ++- .../nlp/AbstractItemIntentInterpreter.java | 63 +---- .../ui/habot/nlp/ItemNamedAttribute.java | 109 ++++++++ .../nlp/UnsupportedLanguageException.java | 6 +- .../internal/ItemNamedAttributesResolver.java | 260 ++++++++++++++++++ .../nlp/internal/OpenNLPInterpreter.java | 62 +++-- .../internal/skill/ActivateObjectSkill.java | 10 +- .../internal/skill/DeactivateObjectSkill.java | 10 +- .../nlp/internal/skill/GetStatusSkill.java | 10 +- .../skill/HistoryDailyGraphSkill.java | 10 +- .../skill/HistoryHourlyGraphSkill.java | 10 +- .../skill/HistoryLastChangesSkill.java | 10 +- .../skill/HistoryMonthlyGraphSkill.java | 10 +- .../skill/HistoryWeeklyGraphSkill.java | 10 +- .../nlp/internal/skill/SetValueSkill.java | 10 +- .../ui/habot/rest/internal/HABotResource.java | 38 +++ src/main/resources/tagattributes.properties | 74 +++++ .../resources/tagattributes_fr.properties | 74 +++++ web/src/layouts/help/GettingStarted.vue | 3 +- web/src/layouts/itemtable/ItemTable.vue | 48 ++-- web/src/pages/Help.vue | 6 +- 21 files changed, 694 insertions(+), 170 deletions(-) create mode 100644 src/main/java/org/openhab/ui/habot/nlp/ItemNamedAttribute.java create mode 100644 src/main/java/org/openhab/ui/habot/nlp/internal/ItemNamedAttributesResolver.java create mode 100644 src/main/resources/tagattributes.properties create mode 100644 src/main/resources/tagattributes_fr.properties diff --git a/src/main/java/org/openhab/ui/habot/card/CardBuilder.java b/src/main/java/org/openhab/ui/habot/card/CardBuilder.java index 0b6bbf3..6176efc 100644 --- a/src/main/java/org/openhab/ui/habot/card/CardBuilder.java +++ b/src/main/java/org/openhab/ui/habot/card/CardBuilder.java @@ -9,6 +9,7 @@ package org.openhab.ui.habot.card; import java.util.Collection; +import java.util.IllegalFormatConversionException; import java.util.Set; import java.util.stream.Collectors; @@ -184,7 +185,8 @@ public Card buildCard(Intent intent, Collection matchedItems) { } } else { - card.setTitle(getCardTitleFromGroupLabels(tags)); + card.setTitle(String.join(", ", intent.getEntities().values())); + // card.setTitle(getCardTitleFromGroupLabels(tags)); card.setSubtitle(matchedItems.size() + " items"); // TODO: i18n // TODO: detect images and build a HbCarousel with them - for webcams etc. @@ -229,7 +231,8 @@ public Card buildChartCard(Intent intent, Collection matchedItems, String card.setTitle(item.getLabel()); card.setSubtitle(item.getName()); } else { - card.setTitle(getCardTitleFromGroupLabels(tags)); + card.setTitle(String.join(", ", intent.getEntities().values())); + // card.setTitle(getCardTitleFromGroupLabels(tags)); card.setSubtitle(matchedItems.size() + " items"); // TODO: i18n } @@ -261,18 +264,22 @@ private String getCardTitleFromGroupLabels(Set tags) { private String formatState(Item item, State state) throws TransformationException { if (item.getStateDescription() != null) { - StateDescription stateDescription = item.getStateDescription(); - if (stateDescription != null && stateDescription.getPattern() != null) { - String transformedState = TransformationHelper.transform( - FrameworkUtil.getBundle(HistoryLastChangesSkill.class).getBundleContext(), - stateDescription.getPattern(), state.toString()); - if (transformedState.equals(state.toString())) { - return state.format(stateDescription.getPattern()); + try { + StateDescription stateDescription = item.getStateDescription(); + if (stateDescription != null && stateDescription.getPattern() != null) { + String transformedState = TransformationHelper.transform( + FrameworkUtil.getBundle(HistoryLastChangesSkill.class).getBundleContext(), + stateDescription.getPattern(), state.toString()); + if (transformedState.equals(state.toString())) { + return state.format(stateDescription.getPattern()); + } else { + return transformedState; + } + } else { - return transformedState; + return state.toString(); } - - } else { + } catch (IllegalFormatConversionException e) { return state.toString(); } } else { diff --git a/src/main/java/org/openhab/ui/habot/nlp/AbstractItemIntentInterpreter.java b/src/main/java/org/openhab/ui/habot/nlp/AbstractItemIntentInterpreter.java index 67aad9d..756a719 100644 --- a/src/main/java/org/openhab/ui/habot/nlp/AbstractItemIntentInterpreter.java +++ b/src/main/java/org/openhab/ui/habot/nlp/AbstractItemIntentInterpreter.java @@ -9,15 +9,13 @@ package org.openhab.ui.habot.nlp; import java.io.InputStream; -import java.util.Collection; -import java.util.HashSet; import java.util.Set; import java.util.stream.Collectors; -import org.eclipse.smarthome.core.items.GroupItem; import org.eclipse.smarthome.core.items.Item; import org.eclipse.smarthome.core.items.ItemRegistry; import org.openhab.ui.habot.nlp.internal.AnswerFormatter; +import org.openhab.ui.habot.nlp.internal.ItemNamedAttributesResolver; /** * An abstract implmentation of a {@link Skill} with helper methods to find items matching an {@link Intent} @@ -30,11 +28,13 @@ public abstract class AbstractItemIntentInterpreter implements Skill { protected ItemRegistry itemRegistry; + protected ItemNamedAttributesResolver itemNamedAttributesResolver; protected AnswerFormatter answerFormatter; /** - * Returns the items matching the entities in the intent by looking for tags prefixed by "object:" or "location:". - * Group items are expanded and the tags, and tags are inherited to members. + * Returns the items matching the entities in the intent. + * It delegates this task to the {@link ItemNamedAttributesResolver} to find named attributes + * matching the entities. * * The resulting items should match the object AND the location if both are provided. * @@ -42,56 +42,10 @@ public abstract class AbstractItemIntentInterpreter implements Skill { * @return the set of matching items */ protected Set findItems(Intent intent) { - Collection itemsWithLocationTag = null; - if (intent.entities.containsKey("location")) { - itemsWithLocationTag = itemRegistry.getItemsByTag("location:" + intent.entities.get("location")); - } - - Collection itemsWithObjectTag = null; - if (intent.entities.containsKey("object")) { - itemsWithObjectTag = itemRegistry.getItemsByTag("object:" + intent.entities.get("object")); - } - - HashSet itemsMatchingLocationSlot = null; - if (itemsWithLocationTag != null) { - itemsMatchingLocationSlot = new HashSet(); - for (Item item : itemsWithLocationTag) { - if (item instanceof GroupItem) { - GroupItem groupItem = (GroupItem) item; - for (Item member : groupItem.getAllMembers()) { - itemsMatchingLocationSlot.add(member); - } - } else { - itemsMatchingLocationSlot.add(item); - } - } - } + String object = intent.getEntities().get("object"); + String location = intent.getEntities().get("location"); - HashSet itemsMatchingObjectSlot = null; - if (itemsWithObjectTag != null) { - itemsMatchingObjectSlot = new HashSet(); - for (Item item : itemsWithObjectTag) { - if (item instanceof GroupItem) { - GroupItem groupItem = (GroupItem) item; - for (Item member : groupItem.getAllMembers()) { - itemsMatchingObjectSlot.add(member); - } - } else { - itemsMatchingObjectSlot.add(item); - } - } - } - - if (itemsMatchingLocationSlot == null && itemsMatchingObjectSlot == null) { - return null; - } else if (itemsMatchingObjectSlot == null) { - return itemsMatchingLocationSlot; - } else if (itemsMatchingLocationSlot == null) { - return itemsMatchingObjectSlot; - } else { - return itemsMatchingLocationSlot.stream().filter(itemsMatchingObjectSlot::contains) - .collect(Collectors.toSet()); - } + return this.itemNamedAttributesResolver.getMatchingItems(object, location).collect(Collectors.toSet()); } @Override @@ -107,5 +61,4 @@ public InputStream getTrainingData(String language) throws UnsupportedLanguageEx return trainingData; } - } diff --git a/src/main/java/org/openhab/ui/habot/nlp/ItemNamedAttribute.java b/src/main/java/org/openhab/ui/habot/nlp/ItemNamedAttribute.java new file mode 100644 index 0000000..546bad9 --- /dev/null +++ b/src/main/java/org/openhab/ui/habot/nlp/ItemNamedAttribute.java @@ -0,0 +1,109 @@ +/** + * Copyright (c) 2010-2018 by the respective copyright holders. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.openhab.ui.habot.nlp; + +public class ItemNamedAttribute { + public enum AttributeSource { + TAG, + METADATA + } + + public ItemNamedAttribute(String type, String value, boolean inherited, AttributeSource source) { + super(); + this.type = type; + this.value = value; + this.inherited = inherited; + this.source = source; + } + + String type; + String value; + boolean inherited; + AttributeSource source; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public boolean isInherited() { + return inherited; + } + + public void setInherited(boolean inherited) { + this.inherited = inherited; + } + + public AttributeSource getSource() { + return source; + } + + public void setSource(AttributeSource source) { + this.source = source; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (inherited ? 1231 : 1237); + result = prime * result + ((source == null) ? 0 : source.hashCode()); + result = prime * result + ((type == null) ? 0 : type.hashCode()); + result = prime * result + ((value == null) ? 0 : value.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + ItemNamedAttribute other = (ItemNamedAttribute) obj; + // doesn't matter + // if (inherited != other.inherited) { + // return false; + // } + // if (source != other.source) { + // return false; + // } + if (type == null) { + if (other.type != null) { + return false; + } + } else if (!type.equals(other.type)) { + return false; + } + if (value == null) { + if (other.value != null) { + return false; + } + } else if (!value.equals(other.value)) { + return false; + } + return true; + } + +} diff --git a/src/main/java/org/openhab/ui/habot/nlp/UnsupportedLanguageException.java b/src/main/java/org/openhab/ui/habot/nlp/UnsupportedLanguageException.java index 5c75ad1..1907c7e 100644 --- a/src/main/java/org/openhab/ui/habot/nlp/UnsupportedLanguageException.java +++ b/src/main/java/org/openhab/ui/habot/nlp/UnsupportedLanguageException.java @@ -31,8 +31,12 @@ public UnsupportedLanguageException(String language) { this.language = Locale.forLanguageTag(language); } + public UnsupportedLanguageException(Locale locale) { + this.language = locale; + } + @Override public String getMessage() { - return "Unsupported language: " + language.toString(); + return String.format("Unsupported language: %s", language.toString()); } } diff --git a/src/main/java/org/openhab/ui/habot/nlp/internal/ItemNamedAttributesResolver.java b/src/main/java/org/openhab/ui/habot/nlp/internal/ItemNamedAttributesResolver.java new file mode 100644 index 0000000..eed756b --- /dev/null +++ b/src/main/java/org/openhab/ui/habot/nlp/internal/ItemNamedAttributesResolver.java @@ -0,0 +1,260 @@ +/** + * Copyright (c) 2010-2018 by the respective copyright holders. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.openhab.ui.habot.nlp.internal; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Locale; +import java.util.Map; +import java.util.MissingResourceException; +import java.util.ResourceBundle; +import java.util.Set; +import java.util.stream.Stream; + +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.smarthome.core.common.registry.RegistryChangeListener; +import org.eclipse.smarthome.core.items.GroupItem; +import org.eclipse.smarthome.core.items.Item; +import org.eclipse.smarthome.core.items.ItemRegistry; +import org.eclipse.smarthome.core.items.Metadata; +import org.eclipse.smarthome.core.items.MetadataKey; +import org.eclipse.smarthome.core.items.MetadataRegistry; +import org.openhab.ui.habot.nlp.ItemNamedAttribute; +import org.openhab.ui.habot.nlp.ItemNamedAttribute.AttributeSource; +import org.openhab.ui.habot.nlp.UnsupportedLanguageException; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class retrieves and caches sets of {@link ItemNamedAttribute} mapped to items. + * It uses semantic tags and additional monikers defined in metadata ("habot" namespace). + * The named attributes sourced from tags will be translated to the current language as + * specified. Inheritance is always applied for metadata, while for tags it can be preventing + * with the "inheritTags" configuration property in the "habot" metadata namespace. + * + * @author Yannick Schaus + */ +@Component(service = ItemNamedAttributesResolver.class, immediate = true) +public class ItemNamedAttributesResolver { + + private final Logger logger = LoggerFactory.getLogger(ItemNamedAttributesResolver.class); + + private ItemRegistry itemRegistry; + private MetadataRegistry metadataRegistry; + private Map> itemAttributes; + private Locale currentLocale = null; + ResourceBundle tagAttributes; + + /** + * Sets the current locale. + * Attributes derived from semantic tags will use this locale. + * This will invalidate the attribute cache. + * + * @param locale + */ + public void setLocale(Locale locale) { + if (!locale.equals(currentLocale)) { + this.currentLocale = locale; + logger.debug("Language set to: %s - invalidating cached item named attributes", locale.getLanguage()); + this.itemAttributes = null; + this.tagAttributes = ResourceBundle.getBundle("tagattributes", locale, + ResourceBundle.Control.getNoFallbackControl(ResourceBundle.Control.FORMAT_DEFAULT)); + + } + } + + /** + * Returns a map of all named attributes by item. + * + * @return attributes mapped by item + * @throws UnsupportedLanguageException + */ + public Map> getAllItemNamedAttributes() throws UnsupportedLanguageException { + if (currentLocale == null) { + throw new UnsupportedLanguageException(currentLocale); + } + + if (itemAttributes == null) { + updateItemNamedAttributes(); + } + + return itemAttributes; + } + + /** + * Returns items having attributes matching the provided object and locations. + * Both have to match if provided. + * + * @param object the object to find in the attributes + * @param location the location to find in the attribute + * @return a stream of matching items (groups included) + */ + public Stream getMatchingItems(String object, String location) { + return itemAttributes.entrySet().stream().filter(entry -> { + boolean objectMatch = false; + boolean locationMatch = false; + + if (object != null && entry.getValue().stream() + .anyMatch(a -> a.getValue().toLowerCase().equals(object.toLowerCase()))) { + objectMatch = true; + } + if (location != null && entry.getValue().stream() + .anyMatch(a -> a.getValue().toLowerCase().equals(location.toLowerCase()))) { + locationMatch = true; + } + + return (object != null && location != null) ? objectMatch && locationMatch : objectMatch || locationMatch; + }).map(entry -> entry.getKey()); + } + + private void updateItemNamedAttributes() { + itemAttributes = new HashMap>(); + for (Item item : itemRegistry.getAll()) { + + Metadata metadata = metadataRegistry.get(new MetadataKey("habot", item.getName())); + + // look for semantic tags + for (String tag : item.getTags()) { + if (tag.split(":").length != 2) { + continue; + } + + String type = tag.startsWith("location:") ? "location" : "object"; + + String semanticTagNamedAttributes; + try { + boolean inheritTag = true; + if (metadata != null && metadata.getConfiguration().containsKey("inheritTags")) { + inheritTag = (boolean) metadata.getConfiguration().get("inheritTags"); + } + semanticTagNamedAttributes = this.tagAttributes.getString(tag.split(":")[1].toLowerCase()); + for (String tagAttribute : semanticTagNamedAttributes.split(",")) { + addItemAttribute(item, type, tagAttribute.trim(), AttributeSource.TAG, false, inheritTag); + } + } catch (MissingResourceException e) { + logger.debug("No named attributes found for tag {}", tag); + } + } + + // look for additional comma-separated item monikers in the "habot" metadata namespace + if (metadata != null && !(metadata.getValue().isEmpty())) { + String type = "object"; + + if (item instanceof GroupItem && item.getTags().stream().anyMatch(t -> t.startsWith("location:"))) { + type = "location"; + } + if (metadata.getConfiguration().containsKey("type")) { + type = metadata.getConfiguration().get("type").toString(); + } + + for (String moniker : metadata.getValue().split(",")) { + // monikers in metadata ARE inherited + addItemAttribute(item, type, moniker.trim(), AttributeSource.METADATA, false, true); + } + } + } + } + + private void addItemAttribute(Item item, String type, String value, AttributeSource source, boolean isInherited, + boolean inheritToGroupMembers) { + Set attributes = itemAttributes.get(item); + if (attributes == null) { + attributes = new HashSet(); + } + + ItemNamedAttribute attribute = new ItemNamedAttribute(type, value, isInherited, source); + attributes.add(attribute); + + if (item instanceof GroupItem && inheritToGroupMembers) { + for (Item groupMemberItem : ((GroupItem) item).getMembers(i -> true)) { + addItemAttribute(groupMemberItem, type, value, source, true, true); + } + } + + itemAttributes.put(item, attributes); + } + + @Reference + protected void setItemRegistry(ItemRegistry itemRegistry) { + if (this.itemRegistry == null) { + this.itemRegistry = itemRegistry; + this.itemRegistry.addRegistryChangeListener(registryChangeListener); + } + } + + protected void unsetItemRegistry(ItemRegistry itemRegistry) { + if (itemRegistry == this.itemRegistry) { + this.itemRegistry.removeRegistryChangeListener(registryChangeListener); + this.itemRegistry = null; + } + } + + @Reference + protected void setMetadataRegistry(MetadataRegistry metadataRegistry) { + if (this.metadataRegistry == null) { + this.metadataRegistry = metadataRegistry; + this.metadataRegistry.addRegistryChangeListener(metadataRegistryChangeListener); + } + } + + protected void unsetMetadataRegistry(MetadataRegistry metadataRegistry) { + if (metadataRegistry == this.metadataRegistry) { + this.metadataRegistry.removeRegistryChangeListener(metadataRegistryChangeListener); + this.metadataRegistry = null; + } + } + + private @NonNull RegistryChangeListener registryChangeListener = new RegistryChangeListener() { + @Override + public void added(Item element) { + logger.debug("Invalidating cached item named attributes"); + itemAttributes = null; + } + + @Override + public void removed(Item element) { + logger.debug("Invalidating cached item named attributes"); + itemAttributes = null; + } + + @Override + public void updated(Item oldElement, Item element) { + logger.debug("Invalidating cached item named attributes"); + itemAttributes = null; + } + }; + + private @NonNull RegistryChangeListener metadataRegistryChangeListener = new RegistryChangeListener() { + @Override + public void added(Metadata element) { + if (element.getUID().getNamespace() == "habot") { + logger.debug("Invalidating cached item named attributes"); + itemAttributes = null; + } + } + + @Override + public void removed(Metadata element) { + if (element.getUID().getNamespace() == "habot") { + logger.debug("Invalidating cached item named attributes"); + itemAttributes = null; + } + } + + @Override + public void updated(Metadata oldElement, Metadata element) { + if (element.getUID().getNamespace() == "habot") { + logger.debug("Invalidating cached item named attributes"); + itemAttributes = null; + } + } + }; +} diff --git a/src/main/java/org/openhab/ui/habot/nlp/internal/OpenNLPInterpreter.java b/src/main/java/org/openhab/ui/habot/nlp/internal/OpenNLPInterpreter.java index 98c4558..9e85f3f 100644 --- a/src/main/java/org/openhab/ui/habot/nlp/internal/OpenNLPInterpreter.java +++ b/src/main/java/org/openhab/ui/habot/nlp/internal/OpenNLPInterpreter.java @@ -10,7 +10,6 @@ import java.io.InputStream; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; @@ -19,6 +18,7 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.commons.io.IOUtils; import org.eclipse.jdt.annotation.NonNull; @@ -31,7 +31,9 @@ import org.openhab.ui.habot.nlp.ChatReply; import org.openhab.ui.habot.nlp.Intent; import org.openhab.ui.habot.nlp.IntentInterpretation; +import org.openhab.ui.habot.nlp.ItemNamedAttribute; import org.openhab.ui.habot.nlp.Skill; +import org.openhab.ui.habot.nlp.UnsupportedLanguageException; import org.osgi.framework.BundleContext; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; @@ -51,7 +53,7 @@ "service.config.category=voice" }) public class OpenNLPInterpreter implements HumanLanguageInterpreter { - private static final Set SUPPORTED_LOCALES = Collections + public static final Set SUPPORTED_LOCALES = Collections .unmodifiableSet(new HashSet<>(Arrays.asList(Locale.ENGLISH, Locale.FRENCH, Locale.GERMAN))); private IntentTrainer intentTrainer = null; @@ -59,6 +61,7 @@ public class OpenNLPInterpreter implements HumanLanguageInterpreter { private String tokenizerId = null; private ItemRegistry itemRegistry; + private ItemNamedAttributesResolver itemNamedAttributesResolver; private EventPublisher eventPublisher; private HashMap skills = new HashMap(); @@ -66,25 +69,17 @@ public class OpenNLPInterpreter implements HumanLanguageInterpreter { private @NonNull RegistryChangeListener registryChangeListener = new RegistryChangeListener() { @Override public void added(Item element) { - // Only invalidate the trainer if the new item has tags - if (element.getTags().stream().anyMatch(tag -> tag.startsWith("object:") || tag.startsWith("location:"))) { - intentTrainer = null; - } + intentTrainer = null; } @Override public void removed(Item element) { - // Only invalidate the trainer if the removed item had tags - if (element.getTags().stream().anyMatch(tag -> tag.startsWith("object:") || tag.startsWith("location:"))) { - intentTrainer = null; - } + intentTrainer = null; } @Override public void updated(Item oldElement, Item element) { - if (!element.getTags().equals(oldElement.getTags())) { - intentTrainer = null; - } + intentTrainer = null; } }; @@ -108,18 +103,20 @@ public String interpret(Locale locale, String text) throws InterpretationExcepti return reply.getAnswer(); } - private InputStream getNameFinderTrainingDataFromTags() { + private InputStream getNameSamplesFromItems(Locale locale) throws UnsupportedLanguageException { StringBuilder nameSamplesDoc = new StringBuilder(); - Collection items = itemRegistry.getItems(); - for (Item item : items) { - for (String tag : item.getTags()) { - if (tag.startsWith("object:")) { - nameSamplesDoc.append(String.format(" %s %n", tag.split(":")[1])); - } else if (tag.startsWith("location:")) { - nameSamplesDoc.append(String.format(" %s %n", tag.split(":")[1])); - } + itemNamedAttributesResolver.setLocale(locale); + Map> itemAttributes = itemNamedAttributesResolver.getAllItemNamedAttributes(); + + Stream attributes = itemAttributes.values().stream().flatMap(a -> a.stream()); + + attributes.forEach(attribute -> { + if (attribute.getType() == "location") { + nameSamplesDoc.append(String.format(" %s %n", attribute.getValue())); + } else { + nameSamplesDoc.append(String.format(" %s %n", attribute.getValue())); } - } + }); return IOUtils.toInputStream(nameSamplesDoc.toString()); } @@ -149,7 +146,7 @@ public int compare(Skill o1, Skill o2) { return o1.getIntentId().compareTo(o2.getIntentId()); } - }).collect(Collectors.toList()), getNameFinderTrainingDataFromTags(), this.tokenizerId); + }).collect(Collectors.toList()), getNameSamplesFromItems(locale), this.tokenizerId); currentLocale = locale; } catch (Exception e) { InterpretationException fe = new InterpretationException( @@ -163,10 +160,10 @@ public int compare(Skill o1, Skill o2) { Intent intent; - // Shortcut: if there are any items whose object: or location: tags match the query (case insensitive), consider - // it a "get-status" intent with this tags as the corresponding entity. - // This allows the user to query a tag quickly by simply stating it - and avoid a misinterpretation by the - // categorizer. + // Shortcut: if there are any items whose named attributes match the query (case insensitive), consider + // it a "get-status" intent with this attribute as the corresponding entity. + // This allows the user to query a named attribute quickly by simply stating it - and avoid a + // misinterpretation by the categorizer. if (!this.itemRegistry.getItemsByTag("object:" + text.toLowerCase()).isEmpty()) { intent = new Intent("get-status"); intent.setEntities(new HashMap()); @@ -232,6 +229,15 @@ protected void unsetItemRegistry(ItemRegistry itemRegistry) { } } + @Reference + protected void setItemNamedAttributesResolver(ItemNamedAttributesResolver itemNamedAttributesResolver) { + this.itemNamedAttributesResolver = itemNamedAttributesResolver; + } + + protected void unsetItemNamedAttributesResolver(ItemNamedAttributesResolver itemNamedAttributesResolver) { + this.itemNamedAttributesResolver = null; + } + @Reference protected void setEventPublisher(EventPublisher eventPublisher) { if (this.eventPublisher == null) { diff --git a/src/main/java/org/openhab/ui/habot/nlp/internal/skill/ActivateObjectSkill.java b/src/main/java/org/openhab/ui/habot/nlp/internal/skill/ActivateObjectSkill.java index ca4d6d6..ea76724 100644 --- a/src/main/java/org/openhab/ui/habot/nlp/internal/skill/ActivateObjectSkill.java +++ b/src/main/java/org/openhab/ui/habot/nlp/internal/skill/ActivateObjectSkill.java @@ -14,7 +14,6 @@ import org.eclipse.smarthome.core.events.EventPublisher; import org.eclipse.smarthome.core.items.Item; -import org.eclipse.smarthome.core.items.ItemRegistry; import org.eclipse.smarthome.core.items.events.ItemEventFactory; import org.eclipse.smarthome.core.library.types.OnOffType; import org.openhab.ui.habot.card.CardBuilder; @@ -22,6 +21,7 @@ import org.openhab.ui.habot.nlp.Intent; import org.openhab.ui.habot.nlp.IntentInterpretation; import org.openhab.ui.habot.nlp.Skill; +import org.openhab.ui.habot.nlp.internal.ItemNamedAttributesResolver; import org.osgi.service.component.annotations.Reference; import com.google.common.collect.ImmutableMap; @@ -93,12 +93,12 @@ protected void unsetCardBuilder(CardBuilder cardBuilder) { } @Reference - protected void setItemRegistry(ItemRegistry itemRegistry) { - this.itemRegistry = itemRegistry; + protected void setItemNamedAttributesResolver(ItemNamedAttributesResolver itemNamedAttributesResolver) { + this.itemNamedAttributesResolver = itemNamedAttributesResolver; } - protected void unsetItemRegistry(ItemRegistry itemRegistry) { - this.itemRegistry = null; + protected void unsetItemNamedAttributesResolver(ItemNamedAttributesResolver itemNamedAttributesResolver) { + this.itemNamedAttributesResolver = null; } @Reference diff --git a/src/main/java/org/openhab/ui/habot/nlp/internal/skill/DeactivateObjectSkill.java b/src/main/java/org/openhab/ui/habot/nlp/internal/skill/DeactivateObjectSkill.java index 0727ee2..0ebc7f6 100644 --- a/src/main/java/org/openhab/ui/habot/nlp/internal/skill/DeactivateObjectSkill.java +++ b/src/main/java/org/openhab/ui/habot/nlp/internal/skill/DeactivateObjectSkill.java @@ -14,7 +14,6 @@ import org.eclipse.smarthome.core.events.EventPublisher; import org.eclipse.smarthome.core.items.Item; -import org.eclipse.smarthome.core.items.ItemRegistry; import org.eclipse.smarthome.core.items.events.ItemEventFactory; import org.eclipse.smarthome.core.library.types.OnOffType; import org.openhab.ui.habot.card.CardBuilder; @@ -22,6 +21,7 @@ import org.openhab.ui.habot.nlp.Intent; import org.openhab.ui.habot.nlp.IntentInterpretation; import org.openhab.ui.habot.nlp.Skill; +import org.openhab.ui.habot.nlp.internal.ItemNamedAttributesResolver; import org.osgi.service.component.annotations.Reference; import com.google.common.collect.ImmutableMap; @@ -93,12 +93,12 @@ protected void unsetCardBuilder(CardBuilder cardBuilder) { } @Reference - protected void setItemRegistry(ItemRegistry itemRegistry) { - this.itemRegistry = itemRegistry; + protected void setItemNamedAttributesResolver(ItemNamedAttributesResolver itemNamedAttributesResolver) { + this.itemNamedAttributesResolver = itemNamedAttributesResolver; } - protected void unsetItemRegistry(ItemRegistry itemRegistry) { - this.itemRegistry = null; + protected void unsetItemNamedAttributesResolver(ItemNamedAttributesResolver itemNamedAttributesResolver) { + this.itemNamedAttributesResolver = null; } @Reference diff --git a/src/main/java/org/openhab/ui/habot/nlp/internal/skill/GetStatusSkill.java b/src/main/java/org/openhab/ui/habot/nlp/internal/skill/GetStatusSkill.java index 556c53d..1423fed 100644 --- a/src/main/java/org/openhab/ui/habot/nlp/internal/skill/GetStatusSkill.java +++ b/src/main/java/org/openhab/ui/habot/nlp/internal/skill/GetStatusSkill.java @@ -11,12 +11,12 @@ import java.util.Set; import org.eclipse.smarthome.core.items.Item; -import org.eclipse.smarthome.core.items.ItemRegistry; import org.openhab.ui.habot.card.CardBuilder; import org.openhab.ui.habot.nlp.AbstractItemIntentInterpreter; import org.openhab.ui.habot.nlp.Intent; import org.openhab.ui.habot.nlp.IntentInterpretation; import org.openhab.ui.habot.nlp.Skill; +import org.openhab.ui.habot.nlp.internal.ItemNamedAttributesResolver; import org.osgi.service.component.annotations.Reference; /** @@ -62,11 +62,11 @@ protected void unsetCardBuilder(CardBuilder cardBuilder) { } @Reference - protected void setItemRegistry(ItemRegistry itemRegistry) { - this.itemRegistry = itemRegistry; + protected void setItemNamedAttributesResolver(ItemNamedAttributesResolver itemNamedAttributesResolver) { + this.itemNamedAttributesResolver = itemNamedAttributesResolver; } - protected void unsetItemRegistry(ItemRegistry itemRegistry) { - this.itemRegistry = null; + protected void unsetItemNamedAttributesResolver(ItemNamedAttributesResolver itemNamedAttributesResolver) { + this.itemNamedAttributesResolver = null; } } diff --git a/src/main/java/org/openhab/ui/habot/nlp/internal/skill/HistoryDailyGraphSkill.java b/src/main/java/org/openhab/ui/habot/nlp/internal/skill/HistoryDailyGraphSkill.java index 7c45987..1033858 100644 --- a/src/main/java/org/openhab/ui/habot/nlp/internal/skill/HistoryDailyGraphSkill.java +++ b/src/main/java/org/openhab/ui/habot/nlp/internal/skill/HistoryDailyGraphSkill.java @@ -11,12 +11,12 @@ import java.util.Set; import org.eclipse.smarthome.core.items.Item; -import org.eclipse.smarthome.core.items.ItemRegistry; import org.openhab.ui.habot.card.CardBuilder; import org.openhab.ui.habot.nlp.AbstractItemIntentInterpreter; import org.openhab.ui.habot.nlp.Intent; import org.openhab.ui.habot.nlp.IntentInterpretation; import org.openhab.ui.habot.nlp.Skill; +import org.openhab.ui.habot.nlp.internal.ItemNamedAttributesResolver; import org.osgi.service.component.annotations.Reference; /** @@ -68,11 +68,11 @@ protected void unsetCardBuilder(CardBuilder cardBuilder) { } @Reference - protected void setItemRegistry(ItemRegistry itemRegistry) { - this.itemRegistry = itemRegistry; + protected void setItemNamedAttributesResolver(ItemNamedAttributesResolver itemNamedAttributesResolver) { + this.itemNamedAttributesResolver = itemNamedAttributesResolver; } - protected void unsetItemRegistry(ItemRegistry itemRegistry) { - this.itemRegistry = null; + protected void unsetItemNamedAttributesResolver(ItemNamedAttributesResolver itemNamedAttributesResolver) { + this.itemNamedAttributesResolver = null; } } diff --git a/src/main/java/org/openhab/ui/habot/nlp/internal/skill/HistoryHourlyGraphSkill.java b/src/main/java/org/openhab/ui/habot/nlp/internal/skill/HistoryHourlyGraphSkill.java index 24c205a..1ec1c60 100644 --- a/src/main/java/org/openhab/ui/habot/nlp/internal/skill/HistoryHourlyGraphSkill.java +++ b/src/main/java/org/openhab/ui/habot/nlp/internal/skill/HistoryHourlyGraphSkill.java @@ -11,12 +11,12 @@ import java.util.Set; import org.eclipse.smarthome.core.items.Item; -import org.eclipse.smarthome.core.items.ItemRegistry; import org.openhab.ui.habot.card.CardBuilder; import org.openhab.ui.habot.nlp.AbstractItemIntentInterpreter; import org.openhab.ui.habot.nlp.Intent; import org.openhab.ui.habot.nlp.IntentInterpretation; import org.openhab.ui.habot.nlp.Skill; +import org.openhab.ui.habot.nlp.internal.ItemNamedAttributesResolver; import org.osgi.service.component.annotations.Reference; /** @@ -68,11 +68,11 @@ protected void unsetCardBuilder(CardBuilder cardBuilder) { } @Reference - protected void setItemRegistry(ItemRegistry itemRegistry) { - this.itemRegistry = itemRegistry; + protected void setItemNamedAttributesResolver(ItemNamedAttributesResolver itemNamedAttributesResolver) { + this.itemNamedAttributesResolver = itemNamedAttributesResolver; } - protected void unsetItemRegistry(ItemRegistry itemRegistry) { - this.itemRegistry = null; + protected void unsetItemNamedAttributesResolver(ItemNamedAttributesResolver itemNamedAttributesResolver) { + this.itemNamedAttributesResolver = null; } } diff --git a/src/main/java/org/openhab/ui/habot/nlp/internal/skill/HistoryLastChangesSkill.java b/src/main/java/org/openhab/ui/habot/nlp/internal/skill/HistoryLastChangesSkill.java index 182954b..d848697 100644 --- a/src/main/java/org/openhab/ui/habot/nlp/internal/skill/HistoryLastChangesSkill.java +++ b/src/main/java/org/openhab/ui/habot/nlp/internal/skill/HistoryLastChangesSkill.java @@ -15,7 +15,6 @@ import java.util.stream.Collectors; import org.eclipse.smarthome.core.items.Item; -import org.eclipse.smarthome.core.items.ItemRegistry; import org.eclipse.smarthome.core.persistence.HistoricItem; import org.eclipse.smarthome.core.transform.TransformationException; import org.eclipse.smarthome.core.transform.TransformationHelper; @@ -29,6 +28,7 @@ import org.openhab.ui.habot.nlp.Intent; import org.openhab.ui.habot.nlp.IntentInterpretation; import org.openhab.ui.habot.nlp.Skill; +import org.openhab.ui.habot.nlp.internal.ItemNamedAttributesResolver; import org.osgi.framework.FrameworkUtil; import org.osgi.service.component.annotations.Reference; @@ -135,12 +135,12 @@ private String formatState(Item item, State state) { } @Reference - protected void setItemRegistry(ItemRegistry itemRegistry) { - this.itemRegistry = itemRegistry; + protected void setItemNamedAttributesResolver(ItemNamedAttributesResolver itemNamedAttributesResolver) { + this.itemNamedAttributesResolver = itemNamedAttributesResolver; } - protected void unsetItemRegistry(ItemRegistry itemRegistry) { - this.itemRegistry = null; + protected void unsetItemNamedAttributesResolver(ItemNamedAttributesResolver itemNamedAttributesResolver) { + this.itemNamedAttributesResolver = null; } @Reference diff --git a/src/main/java/org/openhab/ui/habot/nlp/internal/skill/HistoryMonthlyGraphSkill.java b/src/main/java/org/openhab/ui/habot/nlp/internal/skill/HistoryMonthlyGraphSkill.java index 09a4ee8..37895b7 100644 --- a/src/main/java/org/openhab/ui/habot/nlp/internal/skill/HistoryMonthlyGraphSkill.java +++ b/src/main/java/org/openhab/ui/habot/nlp/internal/skill/HistoryMonthlyGraphSkill.java @@ -11,12 +11,12 @@ import java.util.Set; import org.eclipse.smarthome.core.items.Item; -import org.eclipse.smarthome.core.items.ItemRegistry; import org.openhab.ui.habot.card.CardBuilder; import org.openhab.ui.habot.nlp.AbstractItemIntentInterpreter; import org.openhab.ui.habot.nlp.Intent; import org.openhab.ui.habot.nlp.IntentInterpretation; import org.openhab.ui.habot.nlp.Skill; +import org.openhab.ui.habot.nlp.internal.ItemNamedAttributesResolver; import org.osgi.service.component.annotations.Reference; /** @@ -68,11 +68,11 @@ protected void unsetCardBuilder(CardBuilder cardBuilder) { } @Reference - protected void setItemRegistry(ItemRegistry itemRegistry) { - this.itemRegistry = itemRegistry; + protected void setItemNamedAttributesResolver(ItemNamedAttributesResolver itemNamedAttributesResolver) { + this.itemNamedAttributesResolver = itemNamedAttributesResolver; } - protected void unsetItemRegistry(ItemRegistry itemRegistry) { - this.itemRegistry = null; + protected void unsetItemNamedAttributesResolver(ItemNamedAttributesResolver itemNamedAttributesResolver) { + this.itemNamedAttributesResolver = null; } } diff --git a/src/main/java/org/openhab/ui/habot/nlp/internal/skill/HistoryWeeklyGraphSkill.java b/src/main/java/org/openhab/ui/habot/nlp/internal/skill/HistoryWeeklyGraphSkill.java index 335c328..37a3949 100644 --- a/src/main/java/org/openhab/ui/habot/nlp/internal/skill/HistoryWeeklyGraphSkill.java +++ b/src/main/java/org/openhab/ui/habot/nlp/internal/skill/HistoryWeeklyGraphSkill.java @@ -11,12 +11,12 @@ import java.util.Set; import org.eclipse.smarthome.core.items.Item; -import org.eclipse.smarthome.core.items.ItemRegistry; import org.openhab.ui.habot.card.CardBuilder; import org.openhab.ui.habot.nlp.AbstractItemIntentInterpreter; import org.openhab.ui.habot.nlp.Intent; import org.openhab.ui.habot.nlp.IntentInterpretation; import org.openhab.ui.habot.nlp.Skill; +import org.openhab.ui.habot.nlp.internal.ItemNamedAttributesResolver; import org.osgi.service.component.annotations.Reference; /** @@ -68,11 +68,11 @@ protected void unsetCardBuilder(CardBuilder cardBuilder) { } @Reference - protected void setItemRegistry(ItemRegistry itemRegistry) { - this.itemRegistry = itemRegistry; + protected void setItemNamedAttributesResolver(ItemNamedAttributesResolver itemNamedAttributesResolver) { + this.itemNamedAttributesResolver = itemNamedAttributesResolver; } - protected void unsetItemRegistry(ItemRegistry itemRegistry) { - this.itemRegistry = null; + protected void unsetItemNamedAttributesResolver(ItemNamedAttributesResolver itemNamedAttributesResolver) { + this.itemNamedAttributesResolver = null; } } diff --git a/src/main/java/org/openhab/ui/habot/nlp/internal/skill/SetValueSkill.java b/src/main/java/org/openhab/ui/habot/nlp/internal/skill/SetValueSkill.java index 454c68b..f69103c 100644 --- a/src/main/java/org/openhab/ui/habot/nlp/internal/skill/SetValueSkill.java +++ b/src/main/java/org/openhab/ui/habot/nlp/internal/skill/SetValueSkill.java @@ -17,7 +17,6 @@ import org.eclipse.smarthome.core.events.EventPublisher; import org.eclipse.smarthome.core.items.Item; -import org.eclipse.smarthome.core.items.ItemRegistry; import org.eclipse.smarthome.core.items.events.ItemEventFactory; import org.eclipse.smarthome.core.library.types.DecimalType; import org.eclipse.smarthome.core.library.types.HSBType; @@ -27,6 +26,7 @@ import org.openhab.ui.habot.nlp.Intent; import org.openhab.ui.habot.nlp.IntentInterpretation; import org.openhab.ui.habot.nlp.Skill; +import org.openhab.ui.habot.nlp.internal.ItemNamedAttributesResolver; import org.osgi.service.component.annotations.Reference; import com.google.common.collect.ImmutableMap; @@ -159,12 +159,12 @@ protected void unsetCardBuilder(CardBuilder cardBuilder) { } @Reference - protected void setItemRegistry(ItemRegistry itemRegistry) { - this.itemRegistry = itemRegistry; + protected void setItemNamedAttributesResolver(ItemNamedAttributesResolver itemNamedAttributesResolver) { + this.itemNamedAttributesResolver = itemNamedAttributesResolver; } - protected void unsetItemRegistry(ItemRegistry itemRegistry) { - this.itemRegistry = null; + protected void unsetItemNamedAttributesResolver(ItemNamedAttributesResolver itemNamedAttributesResolver) { + this.itemNamedAttributesResolver = null; } @Reference diff --git a/src/main/java/org/openhab/ui/habot/rest/internal/HABotResource.java b/src/main/java/org/openhab/ui/habot/rest/internal/HABotResource.java index 581e4cb..8a6cd8d 100644 --- a/src/main/java/org/openhab/ui/habot/rest/internal/HABotResource.java +++ b/src/main/java/org/openhab/ui/habot/rest/internal/HABotResource.java @@ -11,6 +11,9 @@ import java.security.InvalidParameterException; import java.util.Collection; import java.util.Locale; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.annotation.security.RolesAllowed; import javax.ws.rs.Consumes; @@ -38,7 +41,9 @@ import org.openhab.ui.habot.card.Card; import org.openhab.ui.habot.card.internal.CardRegistry; import org.openhab.ui.habot.nlp.ChatReply; +import org.openhab.ui.habot.nlp.ItemNamedAttribute; import org.openhab.ui.habot.nlp.internal.AnswerFormatter; +import org.openhab.ui.habot.nlp.internal.ItemNamedAttributesResolver; import org.openhab.ui.habot.nlp.internal.OpenNLPInterpreter; import org.openhab.ui.habot.notification.internal.NotificationService; import org.openhab.ui.habot.notification.internal.webpush.Subscription; @@ -54,6 +59,7 @@ import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; +import javafx.util.Pair; /** * This class describes the /habot resource of the REST API. @@ -79,6 +85,8 @@ public class HABotResource implements RESTResource { private CardRegistry cardRegistry; + private ItemNamedAttributesResolver itemNamedAttributesResolver; + @Reference public void setVoiceManager(VoiceManager voiceManager) { this.voiceManager = voiceManager; @@ -115,6 +123,15 @@ public void unsetCardRegistry(CardRegistry cardRegistry) { this.cardRegistry = null; } + @Reference + protected void setItemNamedAttributesResolver(ItemNamedAttributesResolver itemNamedAttributesResolver) { + this.itemNamedAttributesResolver = itemNamedAttributesResolver; + } + + protected void unsetItemNamedAttributesResolver(ItemNamedAttributesResolver itemNamedAttributesResolver) { + this.itemNamedAttributesResolver = null; + } + public static final String PATH_HABOT = "habot"; @GET @@ -161,6 +178,27 @@ public Response chat(@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = return Response.ok(reply).build(); } + @GET + @RolesAllowed({ Role.USER, Role.ADMIN }) + @Path("/attributes") + @Consumes(MediaType.TEXT_PLAIN) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Gets all item named attributes.") + @ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = ChatReply.class), + @ApiResponse(code = 500, message = "An interpretation error occured") }) + public Response chat(@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @ApiParam(value = "language") String language) + throws Exception { + final Locale locale = (this.localeProvider != null) ? this.localeProvider.getLocale() + : LocaleUtil.getLocale(language); + + this.itemNamedAttributesResolver.setLocale(locale); + Stream>> attributes = this.itemNamedAttributesResolver + .getAllItemNamedAttributes().entrySet().stream() + .map(entry -> new Pair>(entry.getKey().getName(), entry.getValue())); + + return Response.ok(attributes.collect(Collectors.toMap(Pair::getKey, Pair::getValue))).build(); + } + @POST @Path("/notifications/subscribe") // TEXT_PLAIN to work around https://github.com/openhab/openhab-cloud/issues/31 diff --git a/src/main/resources/tagattributes.properties b/src/main/resources/tagattributes.properties new file mode 100644 index 0000000..991b237 --- /dev/null +++ b/src/main/resources/tagattributes.properties @@ -0,0 +1,74 @@ +# Objects +battery=Battery,Batteries +blinds=Blinds,Roller shutters,Rollershutters +camera=Camera,Cameras +car=Car,Cars +cleaningrobot=Cleaning robot,Cleaning robots,Vacuum robot,Vacuum Robots,Roomba,Roombas +door=Door,Doors +fan=Fan,Fans +frontdoor=Front door,Frontdoor +garagedoor=Garage door,Garage doors +lightbulb=Bulb,Bulbs,Lightbulb,Lightbulbs,Light,Lights,Lighting +motiondetector=Motion,Motion sensor,Motion sensors,Motion detector,Motion sensors +networkappliance=Network,Server,Servers,Gateway,Gateways,Bridge,Bridges,Router,Routers +poweroutlet=Power,Outlet,Outlets,Power outlet,Power outlets +projector=Projector,Projectors,Beamer,Beamers +radiatorcontrol=Radiator,Radiators +receiver=Receiver,Receivers,Audio Receiver,Audio Receivers,AV Receiver,AV Receivers +remotecontrol=Remote control,Remote controls +screen=Screen,Screens,Television,Televisions,TV,TVs +sensor=Sensor,Sensors +siren=Siren,Sirens +smokefetector=Smoke detector,Smoke detectors +speaker=Speaker,Speakers +valve=Valve,Valves +wallswitch=Wall switch,Wall switches +webservice=Web service,Web Services +window=Window,Windows +whitegood=Washing machine,Washing machines,Dishwasher,Dishwashers,Dryer,Dryers,Fridge,Fridges,Oven,Ovens + +# Locations +cellar=Cellar +livingroom=Livingroom,Living room +kitchen=Kitchen +bedroom=Bedroom,Bedrooms +bath=Bath,Bathroom,Bathrooms +toilet=Toilet,Toilets,WC,WCs +closet=Closet,Closets +dressing=Dressing,Dressings,Dressing room,Dressing rooms +office=Office,Offices +groundfloor=Ground floor +firstfloor=First floor +attic=Attic +corridor=Corridor,Corridors +garage=Garage,Garages + +# Properties +temperature=Temperature,Temperatures +light=Light,Lights,Lighting +humidity=Humidity,Moisture +presence=Presence +smoke=Smoke +noise=Noise +rain=Rain +wind=Wind +water=Water +co2=CO2,carbon dioxyde +co=CO,carbon monoxyde +energy=Energy +power=Power +voltage=Voltage +current=Current +frequency=Frequency +gas=Gas +oil=Oil + +# Purpose +alarm=Alarm,Alarms +firealarm=Fire alarm,Fire alarms +leakage=Leakage alarm,Leakage alarms +intrusion=Intrusion alarm,Intrusion alarms +coalarm=CO alarm,CO alarms,carbon monoxyde alarm,carbon monoxyde alarms +heating=Heating,Radiators,Climate +cooling=Cooling +presence=Presence diff --git a/src/main/resources/tagattributes_fr.properties b/src/main/resources/tagattributes_fr.properties new file mode 100644 index 0000000..9fd31b9 --- /dev/null +++ b/src/main/resources/tagattributes_fr.properties @@ -0,0 +1,74 @@ +# Objects +battery=batterie,batteries +blinds=store,stores,volet,volets +camera=caméra,caméras +car=voiture,voitures +cleaningrobot=robot ménager,robots ménagers,robot aspirateur,robots aspirateurs,roomba,roombas +door=porte,portes +fan=ventilateur,ventilateurs +frontdoor=porte d'entrée,portes d'entrée +garagedoor=porte de garage,porte du garage,portes de garage,portes des garages +lightbulb=ampoule,ampoules,lumière,lumières,lampe,lampes +motiondetector=mouvement,détecteur de mouvement,détecteurs de mouvement,détection de mouvement +networkappliance=réseau,serveur,serveurs,routeur,routeurs +poweroutlet=prise,prises,prise de courant,prises de courant +projector=projecteur,projecteurs +radiatorcontrol=radiateur,radiateurs +receiver=amplificateur,amplificateurs,récepteur,récepteurs +remotecontrol=télécommande,télécommandes +screen=écran,écrans,télé,télés,télévision,télévisions,tv,tvs +sensor=capteur,capteurs +siren=sirène,sirènes +smokefetector=fumée,détecteur de fumée,détecteurs de fumée,détection de fumée +speaker=enceinte,enceintes +valve=valve,valves +wallswitch=interrupteur,interrupteur,interrupteur mural,interrupteur muraux +webservice=web service,web services +window=fenêtre,fenêtres +whitegood=machine à laver,machines à laver,lave vaiselle,lave vaisselles,sèche linge,sèche linges,réfrigérateur,réfrigérateurs,frigo,frigos,four,fours + +# Locations +cellar=cave +livingroom=salon,séjour +kitchen=cuisine +bedroom=chambre,chambre à coucher,chambres,chambres à coucher +bath=salle de bain,salles de bain +toilet=toilettes,WC,WCs +closet=placard,placards +dressing=dressing,dressings,vestiaire,vestiaires +office=bureau,bureaux +groundfloor=rez de chaussée +firstfloor=premier étage +attic=grenier +corridor=couloir,couloirs +garage=garage,garages + +# Properties +temperature=température,températures +light=lumière,lumières,lampes,éclairage +humidity=humidité +presence=présence +smoke=fumée +noise=bruit +rain=pluie +wind=vent +water=eau +co2=CO2,dioxyde de carbone +co=CO,monoxyde de carbone +energy=énergie +power=puissance,électricité +voltage=Voltage +current=courange +frequency=fréquence +gas=gaz +oil=fioul,fuel,pétrole + +# Purpose +alarm=alarme,alarmes +firealarm=alarme incendie,alarmes incendie +leakage=alarme fuite,alarmes fuites +intrusion=alarme intrusion,alarmes intrusion +coalarm=alarme CO,alarmes CO,alarme monoxyde de carbone,alarmes monoxyde de carbone +heating=chauffage,radiateur,thermostat +cooling=air conditionné +presence=présence diff --git a/web/src/layouts/help/GettingStarted.vue b/web/src/layouts/help/GettingStarted.vue index fedcf52..7dd80c4 100644 --- a/web/src/layouts/help/GettingStarted.vue +++ b/web/src/layouts/help/GettingStarted.vue @@ -158,9 +158,10 @@

To be helpful, I need you to prepare your items first so I can figure out how they are related to your queries
In the next tutorial, I'll tell you all about it!
- Go + Go or Close
+

- - {{ tag }} - - - {{ tag }} - - - {{ group }} + + + {{ attribute.value }} + @@ -71,13 +70,11 @@ export default { { name: 'name', field: 'name', label: 'Name', align: 'left', sortable: true, required: true }, { name: 'type', field: 'type', label: 'Type', align: 'center', sortable: true }, { name: 'label', field: 'label', label: 'Label', align: 'left', sortable: true }, - { name: 'groups', field: 'groupNames', label: 'Groups', align: 'left', sortable: true }, - { name: 'tags', field: 'tags', label: 'Direct Tags', align: 'left', sortable: true, required: true }, - { name: 'inheritedTags', field: 'inheritedTags', label: 'Inherited Tags', align: 'left', sortable: true, required: true } + { name: 'attributes', field: 'attributes', label: 'Attributes', sortable: true } ], items: [], filter: '', - visibleColumns: ['name', 'type', 'label', 'groups', 'tags'], + visibleColumns: ['name', 'type', 'label', 'attributes'], selected: [] } }, @@ -100,21 +97,22 @@ export default { } }, processItems () { - let items = extend(true, [], this.$store.state.items.items).map(i => { - let ret = { - name: i.name, - type: i.type, - label: i.label, - groupNames: i.groupNames, - tags: i.tags - } + this.$http.get('/rest/habot/attributes').then((response) => { + let items = extend(true, [], this.$store.state.items.items).map(i => { + let ret = { + name: i.name, + type: i.type, + label: i.label, + attributes: response.data[i.name] + } - let inheritedTags = [] - this.addInheritedTags(i, inheritedTags, true) - ret.inheritedTags = inheritedTags - return ret + let inheritedTags = [] + this.addInheritedTags(i, inheritedTags, true) + ret.inheritedTags = inheritedTags + return ret + }) + this.items = items }) - this.items = items } }, created () { diff --git a/web/src/pages/Help.vue b/web/src/pages/Help.vue index c1541f8..85c460a 100644 --- a/web/src/pages/Help.vue +++ b/web/src/pages/Help.vue @@ -10,7 +10,7 @@
Essential information
- +
Work with cards
@@ -23,14 +23,14 @@