Skip to content

Commit

Permalink
Items: Support configuration of channellinks and metadata
Browse files Browse the repository at this point in the history
Signed-off-by: Florian Hotze <florianh_dev@icloud.com>
  • Loading branch information
florian-h05 committed Apr 16, 2022
1 parent e8fca79 commit 211ce05
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 37 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -299,8 +299,8 @@ Calling `addItem(itemConfig)` or `replaceItem(itemConfig)` requires the `itemCon
* .category (icon) ⇒ <code>String</code>
* .groups ⇒ <code>Array.&lt;String&gt;</code>
* .tags ⇒ <code>Array.&lt;String&gt;</code>
* .channellink ⇒ <code>String|Array.&lt;String&gt;</code>
* .metadata ⇒ <code>Map</code>
* .channels ⇒ <code>String|Map.&lt;String, Map&lt;String, String&gt;&gt;</code>
* .metadata ⇒ <code>Map&lt;String, Array[]&gt;</code>
* .giBaseType ⇒ <code>String</code>
* .groupFunction ⇒ <code>String</code>

Expand All @@ -309,7 +309,9 @@ Note: `.type` and `.name` are required.
Example:
```javascript
var metadata = new Map();
metadata.set('expire', '10m,state=OFF');
metadata.set('expire', ['10m,state=OFF', new Map().set('ignoreStateUpdates', 'true')]);
var channels = new Map();
channels.set('binding:thing:device:hallway:light', new Map().set('profile', 'system:follow'));

items.replaceItem({
type: 'Switch',
Expand All @@ -318,7 +320,7 @@ items.replaceItem({
category: 'light',
groups: ['Hallway', 'Light'],
tags: ['Lightbulb'],
channellink: 'binding:thing:device:hallway:light',
channels: channels,
metadata: metadata
});
```
Expand Down
31 changes: 18 additions & 13 deletions items/managed.js
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ const createItem = function (itemConfig) {

let baseItem;
if (itemConfig.type === 'Group' && typeof itemConfig.giBaseType !== 'undefined') {
baseItem = itemBuilderFactory.newItemBuilder(itemConfig.giBaseType, itemConfig.name + "_baseItem").build()
baseItem = itemBuilderFactory.newItemBuilder(itemConfig.giBaseType, itemConfig.name + '_baseItem').build();
}
if (itemConfig.type !== 'Group') {
itemConfig.groupFunction = undefined;
Expand Down Expand Up @@ -326,8 +326,8 @@ const createItem = function (itemConfig) {
* @param {String} [itemConfig.category] the category (icon) for the Item
* @param {String[]} [itemConfig.groups] an array of groups the Item is a member of
* @param {String[]} [itemConfig.tags] an array of tags for the Item
* @param {String|String[]} [itemConfig.channellink] a String of one channel link or an array of channel links for the Item
* @param {Map} [itemConfig.metadata] a map of metadata to set on the item
* @param {String|Map<String, Map<String, String>>} [itemConfig.channels] a String of one channel link or a Map: Map<String channel, Map<namespace, value> configuration>
* @param {Map<String, Array[]>} [itemConfig.metadata] Map of metadata: Map<String namespace, Array[String value, Map<String namespace, String value> configuration]>
* @param {HostItem} [itemConfig.giBaseType] the group Item base type for the Item
* @param {HostGroupFunction} [itemConfig.groupFunction] the group function used by the Item
* @returns {Item} an {@link items.Item} object
Expand All @@ -338,14 +338,19 @@ const addItem = function (itemConfig) {
const item = createItem(itemConfig);
managedItemProvider.add(item.rawItem);
if (typeof itemConfig.metadata === 'object') {
for (const [key, value] of itemConfig.metadata) metadata.upsertValue(itemConfig.name, key, value);
for (const [key, value] of itemConfig.metadata) metadata.upsertValue(itemConfig.name, key, value[0], value[1]);
}
if (typeof itemConfig.channellink === 'object') {
for (const i in itemConfig.channels) metadata.itemchannellink.addItemChannelLink(itemConfig.name, itemConfig.channels[i]);
}
if (typeof itemConfig.channellink === 'string') {
metadata.itemchannellink.addItemChannelLink(itemConfig.name, itemConfig.channellink);
if (itemConfig.type !== 'Group') {
if (typeof itemConfig.channels === 'object') { // Map<String channel, Map configuration>
for (const [key, value] of itemConfig.channels) {
metadata.itemchannellink.upsertItemChannelLink(itemConfig.name, key, value);
}
}
if (typeof itemConfig.channels === 'string') {
metadata.itemchannellink.upsertItemChannelLink(itemConfig.name, itemConfig.channels);
}
}

return getItem(itemConfig.name);
};

Expand All @@ -361,7 +366,7 @@ const removeItem = function (itemOrItemName) {

if (typeof itemOrItemName === 'string') {
itemName = itemOrItemName;
} else if (itemOrItemName.hasOwnProperty('name')) {
} else if (itemOrItemName.hasOwnProperty('name')) { // eslint-disable-line no-prototype-builtins
itemName = itemOrItemName.name;
} else {
log.warn('Item not registered (or supplied name is not a string) so cannot be removed');
Expand Down Expand Up @@ -392,16 +397,16 @@ const removeItem = function (itemOrItemName) {
* periodically, during startup or even during development of the script. Using fixed item names will ensure
* that the items remain up-to-date, but won't fail with issues related to duplicate items.
*
* @memberOf items
* @memberOf items
* @param {Object} itemConfig the Item config describing the Item
* @param {String} itemConfig.type the type of the Item
* @param {String} itemConfig.name Item name for the Item to create
* @param {String} [itemConfig.label] the label for the Item
* @param {String} [itemConfig.category] the category (icon) for the Item
* @param {String[]} [itemConfig.groups] an array of groups the Item is a member of
* @param {String[]} [itemConfig.tags] an array of tags for the Item
* @param {String|String[]} [itemConfig.channellink] a String of one channel link or an array of channel links for the Item
* @param {Map} [itemConfig.metadata] a map of metadata to set on the item
* @param {String|Map<String, Map<String, String>>} [itemConfig.channels] a String of one channel link or a Map: Map<String channel, Map<namespace, value> configuration>
* @param {Map<String, Array[]>} [itemConfig.metadata] Map of metadata: Map<String namespace, Array[String value, Map<String namespace, String value> configuration]>
* @param {HostItem} [itemConfig.giBaseType] the group Item base type for the Item
* @param {HostGroupFunction} [itemConfig.groupFunction] the group function used by the Item
* @returns {Item} an {@link items.Item} object
Expand Down
84 changes: 71 additions & 13 deletions metadata/itemchannellink.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const log = require('../log')('itemchannellink');

const ItemChannelLink = Java.type('org.openhab.core.thing.link.ItemChannelLink');
const ChannelUID = Java.type('org.openhab.core.thing.ChannelUID');
const Configuration = Java.type('org.openhab.core.config.core.Configuration');
const managedItemChannelLinkProvider = osgi.getService('org.openhab.core.thing.link.ManagedItemChannelLinkProvider');

/**
Expand All @@ -12,44 +13,101 @@ const managedItemChannelLinkProvider = osgi.getService('org.openhab.core.thing.l
* @memberof metadata
* @param {String} itemName the name of the Item
* @param {String} channel channelUID as string
* @param {Map} [conf] Map of channel configuration
* @returns {ItemChannelLink} ItemChannelLink object
*/
const createItemChannelLink = function (itemName, channel) {
log.debug('Creating item channel link {} -> {}', itemName, channel);
return new ItemChannelLink(itemName, new ChannelUID(channel));
const createItemChannelLink = function (itemName, channel, conf) {
log.debug('Creating Item channel link {} -> {}', itemName, channel);
if (typeof conf === 'object') {
log.debug(' .. with configuration.');
return new ItemChannelLink(itemName, new ChannelUID(channel), new Configuration(conf));
} else {
return new ItemChannelLink(itemName, new ChannelUID(channel));
}
};

/**
* Adds a new ItemChannelLink to the registry. That means, it adds a channel link to a given Item.
* Gets an ItemChannelLink from the provider.
*
* @private
* @memberof metadata
* @param {String} itemName the name of the Item
* @param {String} channel channelUID as string
* @returns {ItemChannelLink|null} if ItemChannelLink is registered in provider, ItemChannelLink, else null
*/
const getItemChannelLink = function (itemName, channel) {
log.debug('Getting Item channel link {} -> {} from provider', itemName, channel);
return managedItemChannelLinkProvider.get(itemName + ' -> ' + channel);
};

/**
* Adds a new ItemChannelLink to the provider. Therefore, it adds a channel link to an Item.
*
* @private
* @memberof metadata
* @param {String} itemName the name of the Item
* @param {String} channel channelUID as string
* @param {Map<String, any>} [conf] Map of channel configuration
* @returns {ItemChannelLink} ItemChannelLink object
*/
const addItemChannelLink = function (itemName, channel) {
log.debug('Adding item channel link {} -> {}', itemName, channel);
const itemChannelLink = createItemChannelLink(itemName, channel);
const addItemChannelLink = function (itemName, channel, conf) {
log.debug('Adding Item channel link {} -> {} to provider', itemName, channel);
const itemChannelLink = createItemChannelLink(itemName, channel, conf);
managedItemChannelLinkProvider.add(itemChannelLink);
return itemChannelLink;
};

/**
* Adds a new ItemChannelLink to the registry. That means, it removes a channel link from a given Item.
* Update an ItemChannelLink in the provider. Therefore, it updates the channel link of an Item.
*
* @private
* @memberof metadata
* @param {String} itemName the name of the Item
* @param {String} channel channelUID as string
* @param {Map<String, String>} [conf] Map of channel configuration
* @returns {ItemChannelLink} ItemChannelLink object
*/
const removeItemChannelLink = function (itemName, channel) {
log.debug('Adding item channel link {} -> {}', itemName, channel);
const itemChannelLink = createItemChannelLink(itemName, channel);
managedItemChannelLinkProvider.remove(itemChannelLink);
const updateItemChannelLink = function (itemName, channel, conf) {
log.debug('Updating Item channel link {} -> {} in provider', itemName, channel);
const itemChannelLink = createItemChannelLink(itemName, channel, conf);
managedItemChannelLinkProvider.update(itemChannelLink);
return itemChannelLink;
};

/**
* Adds (inserts) or updates an Item channel link.
*
* @memberof metadata
* @param {String} itemName the name of the Item
* @param {String} channel channelUID as string
* @param {Map<String, String>} [conf] Map of channel configuration
* @returns true if the channel link was added, false if it was updated
*/
const upsertItemChannelLink = function (itemName, channel, conf) {
const existing = getItemChannelLink(itemName, channel);
if (existing === null) {
addItemChannelLink(itemName, channel, conf);
return true;
} else {
updateItemChannelLink(itemName, channel, conf);
return false;
}
};

/**
* Removes an ItemChannelLink from the provider. Therefore, the channel link is removed from the Item.
*
* @memberof metadata
* @param {String} itemName the name of the Item
* @param {String} channel channelUID as string
* @returns {ItemChannelLink} the removed ItemChannelLink
*/
const removeItemChannelLink = function (itemName, channel) {
log.debug('Removing Item channel link {} -> {} from provider', itemName, channel);
return managedItemChannelLinkProvider.remove(itemName + ' -> ' + channel);
};

module.exports = {
addItemChannelLink,
upsertItemChannelLink,
removeItemChannelLink
};
15 changes: 8 additions & 7 deletions metadata/metadata.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ const getValue = function (itemName, namespace) {
return result ? result.value : null;
};

const addValue = function (itemName, namespace, value) {
const addValue = function (itemName, namespace, value, config) {
const key = new MetadataKey(namespace, itemName);
MetadataRegistry.add(new Metadata(key, value, {}));
MetadataRegistry.add(new Metadata(key, value, config));
};

const updateValue = function (itemName, namespace, value) {
const metadata = createMetadata(itemName, namespace, value);
const updateValue = function (itemName, namespace, value, config) {
const metadata = createMetadata(itemName, namespace, value, config);
const result = MetadataRegistry.update(metadata);
return result ? result.value : null;
};
Expand All @@ -44,16 +44,17 @@ const updateValue = function (itemName, namespace, value) {
* @param {String} itemName the name of the Item
* @param {String} namespace the name of the namespace
* @param {String} value the value to insert or update
* @param {Map<String, String>} [config] configuration of namespace
* @returns {Boolean} true if the value was added, false if it was updated
*/
const upsertValue = function (itemName, namespace, value) {
const upsertValue = function (itemName, namespace, value, config) {
const existing = getValue(itemName, namespace);

if (existing === null) {
addValue(itemName, namespace, value);
addValue(itemName, namespace, value, config);
return true;
} else {
updateValue(itemName, namespace, value);
updateValue(itemName, namespace, value, config);
return false;
}
};
Expand Down

0 comments on commit 211ce05

Please sign in to comment.