diff --git a/README.md b/README.md
index 3783c04a2..f7784a137 100644
--- a/README.md
+++ b/README.md
@@ -32,6 +32,7 @@ binding](https://www.openhab.org/addons/automation/jsscripting/).
- [Paths](#paths)
- [Standard Library](#standard-library)
- [Items](#items)
+ - [Things](#things)
- [Actions](#actions)
- [Cache](#cache)
- [Log](#log)
@@ -393,6 +394,43 @@ var item = items.getItem("KitchenDimmer");
console.log("KitchenDimmer averageSince", item.history.averageSince(yesterday));
```
+### Things
+
+The Things namespace allows to interact with openHAB Things.
+
+See [openhab-js : things](https://openhab.github.io/openhab-js/things.html) for full API documentation.
+
+* things : object
+ * .getItem(uid, nullIfMissing) ⇒ Thing
+ * .Things() ⇒ Array.<Thing>
+
+#### `getThing(uid, nullIfMissing)`
+
+Calling `getThing(...)` returns a `Thing` object with the following properties:
+
+* Thing : object
+ * .bridgeUID ⇒ String
+ * .label ⇒ String
+ * .location ⇒ String
+ * .status ⇒ String
+ * .statusInfo ⇒ String
+ * .thingTypeUID ⇒ String
+ * .uid ⇒ String
+ * .isEnabled ⇒ Boolean
+ * .setLabel(label)
+ * .setLocation(location)
+ * .setProperty(name, value)
+ * .setEnabled(enabled)
+
+```javascript
+const thing = things.getThing('astro:moon:home');
+console.log('Thing label: ' + thing.label);
+// Set Thing location
+thing.setLocation('living room');
+// Disable Thing
+thing.setEnabled(false);
+```
+
### Actions
The actions namespace allows interactions with openHAB actions.
diff --git a/index.js b/index.js
index a607bf053..2c75087b2 100644
--- a/index.js
+++ b/index.js
@@ -13,6 +13,9 @@
/**
* @typedef {Object} HostTrigger Native Jave openHAB Trigger (instance of {@link https://www.openhab.org/javadoc/latest/org/openhab/core/automation/trigger org.openhab.core.automation.Trigger})
*/
+/**
+ * @typedef {Object} HostThing Native Java openHAB Thing (instance of {@link https://www.openhab.org/javadoc/latest/org/openhab/core/thing/thing org.openhab.core.thing.Thing})
+ */
// lazy getters to avoid any reference loading all submodules
module.exports = {
diff --git a/things/things.js b/things/things.js
index 2154ff80c..2a74ffcc7 100644
--- a/things/things.js
+++ b/things/things.js
@@ -1,3 +1,10 @@
+const osgi = require('../osgi');
+const utils = require('../utils');
+const log = require('../log')('things'); // eslint-disable-line no-unused-vars
+
+const thingRegistry = osgi.getService('org.openhab.core.thing.ThingRegistry');
+const thingMgr = osgi.getService('org.openhab.core.thing.ThingManager');
+
const JavaThingBuilder = Java.type('org.openhab.core.thing.binding.builder.ThingBuilder');
const ThingTypeUID = Java.type('org.openhab.core.thing.ThingTypeUID');
const JavaChannelBuilder = Java.type('org.openhab.core.thing.binding.builder.ChannelBuilder');
@@ -7,6 +14,13 @@ const ChannelKind = Java.type('org.openhab.core.thing.type.ChannelKind');
const ChannelTypeUID = Java.type('org.openhab.core.thing.type.ChannelTypeUID');
const Configuration = Java.type('org.openhab.core.config.core.Configuration');
+/**
+ * Things namespace.
+ * This namespace handles querying and editing openHAB Things.
+ *
+ * @namespace things
+ */
+
class OHThing {
constructor (rawThing) {
this.rawThing = rawThing;
@@ -95,7 +109,154 @@ class ChannelBuilder {
}
}
+/**
+ * Class representing an openHAB Thing
+ *
+ * @memberof things
+ */
+class Thing {
+ /**
+ * Create an Thing, wrapping a native Java openHAB Thing. Don't use this constructor, instead call {@link getThing}.
+ * @param {HostThing} rawThing Java Thing from Host
+ * @hideconstructor
+ */
+ constructor (rawThing) {
+ if (typeof rawThing === 'undefined') {
+ throw Error('Supplied Thing is undefined');
+ }
+ this.rawThing = rawThing;
+ }
+
+ /**
+ * Thing's bridge UID as `String`
+ */
+ get bridgeUID () {
+ try {
+ return this.rawThing.getBridgeUID().getID();
+ } catch (error) {
+ // Thing has no bridge
+ }
+ }
+
+ /**
+ * label as `String`
+ */
+ get label () {
+ return this.rawThing.getLabel();
+ }
+
+ /**
+ * physical location as `String`
+ */
+ get location () {
+ return this.rawThing.getLocation();
+ }
+
+ /**
+ * status as `String`
+ */
+ get status () {
+ return this.rawThing.getStatus().toString();
+ }
+
+ /**
+ * status info (more detailed status text) as `String`
+ */
+ get statusInfo () {
+ return this.rawThing.getStatusInfo().toString();
+ }
+
+ /**
+ * Thing type UID as `String`
+ */
+ get thingTypeUID () {
+ return this.rawThing.getThingTypeUID().toString();
+ }
+
+ /**
+ * Thing UID as `String`
+ */
+ get uid () {
+ return this.rawThing.getUID().toString();
+ }
+
+ /**
+ * whether the Thing is enabled or not (`Boolean`)
+ */
+ get isEnabled () {
+ return this.rawThing.isEnabled();
+ }
+
+ /**
+ * Set the label.
+ * @param {String} label Thing label
+ */
+ setLabel (label) {
+ this.rawThing.setLabel(label);
+ }
+
+ /**
+ * Sets the physical location.
+ * @param {String} location physical location of the Thing
+ */
+ setLocation (location) {
+ this.rawThing.setLocation(location);
+ }
+
+ /**
+ * Sets the property value for the property identified by the given name.
+ * @param {String} name name of the property
+ * @param {String} value value for the property
+ */
+ setProperty (name, value) {
+ this.rawThing.setProperty(name, value);
+ }
+
+ /**
+ * Sets the enabled status of the Thing.
+ * @param {Boolean} enabled whether the Thing is enabled or not
+ */
+ setEnabled (enabled) {
+ thingMgr.setEnabled(this.rawThing.getUID(), enabled);
+ }
+}
+
+/**
+ * Gets an openHAB Thing.
+ *
+ * @memberof things
+ * @param {String} uid UID of the thing
+ * @param {Boolean} [nullIfMissing] whether to return null if the Thing cannot be found (default is to throw an exception)
+ * @returns {things.Thing} the Thing
+ */
+const getThing = function (uid, nullIfMissing) {
+ try {
+ if (typeof uid === 'string' || uid instanceof String) {
+ return new Thing(thingRegistry.get(new ThingUID(uid)));
+ }
+ } catch (e) {
+ if (nullIfMissing) {
+ return null;
+ } else {
+ throw e;
+ }
+ }
+};
+
+/**
+ * Gets all openHAB Things.
+ *
+ * @memberof things
+ * @returns {things.Thing[]} all Things
+ */
+const getThings = function () {
+ return utils.javaSetToJsArray(thingRegistry.getAll()).map(i => new Thing(i));
+};
+
module.exports = {
newThingBuilder: (thingTypeUID, id, bridgeUID) => new ThingBuilder(thingTypeUID, id, bridgeUID),
- newChannelBuilder: (thingUID, channelId, acceptedItemType) => new ChannelBuilder(thingUID, channelId, acceptedItemType)
+ newChannelBuilder: (thingUID, channelId, acceptedItemType) => new ChannelBuilder(thingUID, channelId, acceptedItemType),
+ Thing,
+ getThing,
+ getThings
};