Applied several markdown fixes. (#1421)
Signed-off-by: Jerome Luckenbach <github@luckenba.ch>pull/1422/head
parent
00bfdb0031
commit
a41a88225f
|
@ -16,7 +16,6 @@ The full Java API for binding definitions can be found in the Java package `org.
|
|||
|
||||
For the declarative way, you add your binding information in form of a `binding.xml` file to the bundle's folder `/src/main/resources/OH-INF/binding/binding.xml`.
|
||||
|
||||
|
||||
### XML Structure for Binding Definitions
|
||||
|
||||
```xml
|
||||
|
@ -51,7 +50,6 @@ For the declarative way, you add your binding information in form of a `binding.
|
|||
| config-description-ref | The reference to a configuration description for the binding within the ConfigDescriptionRegistry | optional |
|
||||
| config-description-ref.uri | The URI of the configuration description for the binding within the ConfigDescriptionRegistry | mandatory |
|
||||
|
||||
|
||||
The full XML schema for binding definitions is specified in the [Binding XSD](https://openhab.org/schemas/binding-1.0.0.xsd) file.
|
||||
|
||||
**Hints:**
|
||||
|
@ -61,7 +59,6 @@ The full XML schema for binding definitions is specified in the [Binding XSD](ht
|
|||
- Normally the service id must not be defined, because it is implicitly set to "binding.<binding.id>".
|
||||
A binding can register an OSGi service which implements the ManagedService interface and define the service.pid as e.g."binding.hue" to receive the configuration.
|
||||
|
||||
|
||||
### Example
|
||||
|
||||
The following code gives an example for a binding definition.
|
||||
|
|
|
@ -147,10 +147,11 @@ Further, the <strong>item</strong> context can contain criteria to filter the li
|
|||
In the case of above filter only those items will be shown that satisfy the filter's conditions.
|
||||
The above filter is evaluated as follows:
|
||||
|
||||
```
|
||||
```text
|
||||
(type=Switch OR type=Dimmer) AND (tag=Light OR tag=Heating)
|
||||
|
||||
```
|
||||
|
||||
Similarly, the <strong>Channel</strong> context can contain criteria to filter channels based on <strong>kind</strong> field.
|
||||
The value of <strong>kind</strong> can either be STATE or TRIGGER.
|
||||
For example:
|
||||
|
|
|
@ -10,11 +10,11 @@ title: FAQ
|
|||
Here is a list of frequently asked questions around the development of bindings.
|
||||
If you do not find an answer to your question, do not hesitate to ask it on the support forum.
|
||||
|
||||
### Structuring Things and Thing Types
|
||||
## Structuring Things and Thing Types
|
||||
|
||||
1. _I am implementing a binding for system X.
|
||||
Shall I design this as one Thing or as a Bridge with multiple Things for the different functionalities?_
|
||||
|
||||
Shall I design this as one Thing or as a Bridge with multiple Things for the different functionalities?_
|
||||
|
||||
In general, both options are valid:
|
||||
|
||||
1. You have one Thing which has channels for all your actors, sensors and other functions
|
||||
|
@ -24,15 +24,15 @@ Shall I design this as one Thing or as a Bridge with multiple Things for the dif
|
|||
This means that the physical devices should be represented by a Thing each.
|
||||
This only makes sense if your system allows you to identify the different physical devices at all.
|
||||
Especially, such an architecture is useful if you can do a discovery of new devices that could then be presented to the user/admin.
|
||||
|
||||
|
||||
If your system does not provide you any possibility to get hold of such information, but rather only shows you a "logical" view of it, then 1) is also a valid option to pursue.
|
||||
|
||||
|
||||
2. _Do I have to create XML files in `OH-INF/thing` for all devices or is there any other option?_
|
||||
|
||||
No, the XML files are only one way to describe your devices.
|
||||
Alternatively, you can implement your own [ThingTypeProvider](https://github.com/openhab/openhab-core/blob/master/bundles/org.openhab.core.thing/src/main/java/org/openhab/core/thing/binding/ThingTypeProvider.java), through which you can provide thing descriptions in a programmatic way.
|
||||
Nonetheless, the static XML descriptions of thing types can be picked up for documentation generation and other purposes.
|
||||
So whenever possible, static XML descriptions should be provided.
|
||||
So whenever possible, static XML descriptions should be provided.
|
||||
|
||||
3. _For my system XY, there are so many different variants of devices.
|
||||
Do I really need to define a thing type for every single one of them?_
|
||||
|
@ -41,16 +41,16 @@ Do I really need to define a thing type for every single one of them?_
|
|||
The thing types that you provide will be the list the user can choose from.
|
||||
If your system supports auto-discovery and you can also dynamically construct things (and their channels) from structural information that you can access during runtime, there is in theory no need to provide any thing type description at all.
|
||||
Nonetheless, static descriptions of thing types have the advantage that the user knows which kind of devices are supported, no matter if he has a device at home or not - so you should at least have static XML descriptions for the devices that are known to you at implementation time.
|
||||
|
||||
|
||||
4. _I have a device that can have different firmware versions with slightly different functionality.
|
||||
Should I create one or two thing types for it?_
|
||||
|
||||
|
||||
If the firmware version makes a huge difference for the device (and can be seen as a different model of it), then it is ok to have different things defined.
|
||||
If the list of channels can be determined by knowing the firmware revision, this is good.
|
||||
If you can only determine the existing channels by querying the device itself, it might be the better option to have only one thing type and construct its channels upon first access.
|
||||
|
||||
5. _When creating a Thing through my ThingHanderFactory, does it exactly have to have the channels that are defined in the thing type description?_
|
||||
|
||||
|
||||
It must at least have the channels that are defined in its thing type (and they are already automatically added by the super() implementation).
|
||||
Nonetheless, you are free to add any number of additional channels to the thing.
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ It makes sense to briefly read over all sections to make you familiar with what
|
|||
During development you might come back with specific questions.
|
||||
|
||||
{::options toc_levels="2,3"/}
|
||||
* TOC
|
||||
- TOC
|
||||
{:toc}
|
||||
|
||||
## Structure of a Binding
|
||||
|
@ -208,8 +208,8 @@ Inside the `handleCommand` method binding specific logic can be executed.
|
|||
|
||||
The ThingHandler implementation must be prepared to
|
||||
|
||||
* handle different command types depending on the item types, that are defined by the channels,
|
||||
* be called at the same time from different threads.
|
||||
- handle different command types depending on the item types, that are defined by the channels,
|
||||
- be called at the same time from different threads.
|
||||
|
||||
If an exception is thrown in the method, it will be caught by the framework and logged as an error.
|
||||
So it is better to handle communication errors within the binding and to update the thing status accordingly.
|
||||
|
@ -220,19 +220,19 @@ The following code block shows a typical implementation of the `handleCommand` m
|
|||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
try {
|
||||
switch (channelUID.getId()) {
|
||||
case CHANNEL_TEMPERATURE:
|
||||
if(command instanceof OnOffType.class) {
|
||||
// binding specific logic goes here
|
||||
SwitchState deviceSwitchState = convert((OnOffType) command);
|
||||
updateDeviceState(deviceSwitchState);
|
||||
}
|
||||
break;
|
||||
// ...
|
||||
}
|
||||
statusUpdated(ThingStatus.ONLINE);
|
||||
} catch(DeviceCommunicationException ex) {
|
||||
// catch exceptions and handle it in your binding
|
||||
switch (channelUID.getId()) {
|
||||
case CHANNEL_TEMPERATURE:
|
||||
if(command instanceof OnOffType.class) {
|
||||
// binding specific logic goes here
|
||||
SwitchState deviceSwitchState = convert((OnOffType) command);
|
||||
updateDeviceState(deviceSwitchState);
|
||||
}
|
||||
break;
|
||||
// ...
|
||||
}
|
||||
statusUpdated(ThingStatus.ONLINE);
|
||||
} catch(DeviceCommunicationException ex) {
|
||||
// catch exceptions and handle it in your binding
|
||||
statusUpdated(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
@ -356,11 +356,11 @@ All other states are managed by the framework.
|
|||
Furthermore bindings can specify a localized description of the thing status by providing the reference of the localization string, e.g @text/rate_limit.
|
||||
The corresponding handler is able to provide placeholder values as a JSON-serialized array of strings:
|
||||
|
||||
```
|
||||
```text
|
||||
@text/rate_limit ["60", "10", "@text/hour"]
|
||||
```
|
||||
|
||||
```
|
||||
```text
|
||||
rate_limit=Device is blocked by remote service for {0} minutes.
|
||||
Maximum limit of {1} configuration changes per {2} has been exceeded.
|
||||
For further info please refer to device vendor.
|
||||
|
@ -407,7 +407,7 @@ The following example shows how to modify two properties of a thing:
|
|||
|
||||
```java
|
||||
protected void devicePropertiesChanged(DeviceInfo deviceInfo) {
|
||||
Map<String, String> properties = editProperties();
|
||||
Map<String, String> properties = editProperties();
|
||||
properties.put(Thing.PROPERTY_SERIAL_NUMBER, deviceInfo.getSerialNumber());
|
||||
properties.put(Thing.PROPERTY_FIRMWARE_VERSION, deviceInfo.getFirmwareVersion());
|
||||
updateProperties(properties);
|
||||
|
@ -501,7 +501,6 @@ Therefore, the `BridgeHandler` interface extends the `ThingHandler` interface.
|
|||
openHAB provides an abstract implementation of the `BridgeHandler` interface named `BaseBridgeHandler`.
|
||||
It is recommended to use this class, because it covers a lot of common logic.
|
||||
|
||||
|
||||
### Life cycle
|
||||
|
||||
A `BridgeHandler` has the same life cycle than a `ThingHandler` (created by a `ThingHandlerFactory`, well defined life cycle by handler methods `initialize()` and `dispose()`, see chapter [Life Cycle](#lifecycle)).
|
||||
|
@ -534,8 +533,8 @@ A *ThingHandler* as handler for the thing entity can provide the configuration s
|
|||
For things that are created by sub-classes of the `BaseThingHandlerFactory` the provider is already automatically registered as an OSGi service if the concrete thing handler implements the configuration status provider interface.
|
||||
Currently the framework provides two base thing handler implementations for the configuration status provider interface:
|
||||
|
||||
* `org.openhab.core.thing.binding.ConfigStatusThingHandler` extends the `BaseThingHandler` and is to be used if the configuration status is to be provided for thing entities
|
||||
* `org.openhab.core.thing.binding.ConfigStatusBridgeHandler` extends the `BaseBridgeHandler` and is to be used if the configuration status is to be provided for bridge entities
|
||||
- `org.openhab.core.thing.binding.ConfigStatusThingHandler` extends the `BaseThingHandler` and is to be used if the configuration status is to be provided for thing entities
|
||||
- `org.openhab.core.thing.binding.ConfigStatusBridgeHandler` extends the `BaseBridgeHandler` and is to be used if the configuration status is to be provided for bridge entities
|
||||
|
||||
Sub-classes of these handlers must only override the operation `getConfigStatus` to provide the configuration status in form of a collection of `org.openhab.core.config.core.status.ConfigStatusMessage`s.
|
||||
|
||||
|
@ -548,10 +547,10 @@ The actual message key is built by the operation `withMessageKeySuffix(String)`
|
|||
|
||||
As a result depending on the type of the message the final constructed message keys are:
|
||||
|
||||
* config-status.information.any-suffix
|
||||
* config-status.warning.any-suffix
|
||||
* config-status.error.any-suffix
|
||||
* config-status.pending.any-suffix
|
||||
- config-status.information.any-suffix
|
||||
- config-status.warning.any-suffix
|
||||
- config-status.error.any-suffix
|
||||
- config-status.pending.any-suffix
|
||||
|
||||
## Handling Thing / Bridge Removal
|
||||
|
||||
|
@ -572,9 +571,9 @@ Quite often the device or service you expose via openHAB Things allows certain a
|
|||
|
||||
Examples are:
|
||||
|
||||
* Reboot / Restart device
|
||||
* Start searching for new lights for a Hue lights bridge
|
||||
* Send message (via E-Mail / SMS Gateway service / Instant Messanger)
|
||||
- Reboot / Restart device
|
||||
- Start searching for new lights for a Hue lights bridge
|
||||
- Send message (via E-Mail / SMS Gateway service / Instant Messanger)
|
||||
|
||||
If you implement the `ThingActions` interface, you can tell the framework about your Thing related actions.
|
||||
|
||||
|
@ -848,6 +847,7 @@ The devoloper has to take care about that.
|
|||
protected @NonNullByDefault({}) TranslationProvider i18nProvider;
|
||||
protected @NonNullByDefault({}) LocaleProvider localeProvider;
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
### UPnP Discovery
|
||||
|
@ -937,17 +937,17 @@ Various binding related questions are answered in our [Binding development FAQ](
|
|||
|
||||
Once you are happy with your implementation, you need to integrate it in the Maven build and add it to the official distro.
|
||||
|
||||
* Add a new line in the [bundle pom.xml](https://github.com/openhab/openhab-addons/blob/master/bundles/pom.xml).
|
||||
* Add a new line in the [binding pom.xml](https://github.com/openhab/openhab-addons/blob/master/bom/openhab-addons/pom.xml).
|
||||
* If you have a dependency on a transport bundle (e.g. upnp, mdns or serial) or an external library,
|
||||
- Add a new line in the [bundle pom.xml](https://github.com/openhab/openhab-addons/blob/master/bundles/pom.xml).
|
||||
- Add a new line in the [binding pom.xml](https://github.com/openhab/openhab-addons/blob/master/bom/openhab-addons/pom.xml).
|
||||
- If you have a dependency on a transport bundle (e.g. upnp, mdns or serial) or an external library,
|
||||
make sure to add a line for this dependency in the `/src/main/feature/feature.xml` file in your binding folder. See the other bindings as an example.
|
||||
* Add your binding to the [CODEOWNERS](https://github.com/openhab/openhab-addons/blob/master/CODEOWNERS) file so that you get notified by Github when someone adds a pull request towards your binding.
|
||||
- Add your binding to the [CODEOWNERS](https://github.com/openhab/openhab-addons/blob/master/CODEOWNERS) file so that you get notified by Github when someone adds a pull request towards your binding.
|
||||
|
||||
> Please make sure you add the above entries at their alphabetically correct position!
|
||||
|
||||
Before you create a pull request on GitHub, you should now run
|
||||
|
||||
```
|
||||
```bash
|
||||
mvn clean install
|
||||
```
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ These are provided through 'ThingType' and 'ChannelType' definitions,
|
|||
which describe details about their functionality and configuration options.
|
||||
|
||||
{::options toc_levels="2,3"/}
|
||||
* TOC
|
||||
- TOC
|
||||
{:toc}
|
||||
|
||||
## ThingTypeProvider / ChannelTypeProvider
|
||||
|
@ -43,7 +43,7 @@ Which Things can be associated through which bridge type is defined within the d
|
|||
<label>Sample Thing</label>
|
||||
<description>Some sample description</description>
|
||||
<category>Lightbulb</category>
|
||||
...
|
||||
...
|
||||
</thing-type>
|
||||
```
|
||||
|
||||
|
@ -221,7 +221,6 @@ This library is still in development., and only a very small set of tags are def
|
|||
| TargetTemperature | Number, Number:Temperature | A target temperature that should engage a thermostats heating and cooling actions. |
|
||||
| CurrentHumidity | Number | An accessory that provides a single read-only value indicating the relative humidity. |
|
||||
|
||||
|
||||
### State Description
|
||||
|
||||
The state description allows to specify restrictions and additional information for the state of an item, that is linked to the channel.
|
||||
|
@ -232,14 +231,14 @@ The following XML snippet shows the definition for a temperature actuator channe
|
|||
<state min="12" max="30" step="0.5" pattern="%.1f %unit%" readOnly="false"></state>
|
||||
```
|
||||
|
||||
* The attributes `min` and `max` can only be declared for channel with the item type `Number`.
|
||||
- The attributes `min` and `max` can only be declared for channel with the item type `Number`.
|
||||
It defines the range of the numeric value.
|
||||
The Java data type is a BigDecimal.
|
||||
For example user interfaces can create sliders with an appropriate scale based on this information.
|
||||
* The `step` attribute can be declared for `Number` and `Dimmer` items and defines what is the minimal step size that can be used.
|
||||
* The `readonly` attribute can be used for all item types and defines if the state of an item can be changed.
|
||||
- The `step` attribute can be declared for `Number` and `Dimmer` items and defines what is the minimal step size that can be used.
|
||||
- The `readonly` attribute can be used for all item types and defines if the state of an item can be changed.
|
||||
For all sensors the `readonly` attribute should be set to `true`.
|
||||
* The `pattern` attribute can be used for `Number` and `String` items.
|
||||
- The `pattern` attribute can be used for `Number` and `String` items.
|
||||
It gives user interface a hint how to render the item.
|
||||
The format of the pattern must be compliant to the [Java Number Format](https://docs.oracle.com/javase/tutorial/java/data/numberformat.html).
|
||||
The pattern can be localized (see also [Internationalization](../../features/internationalization.html)).
|
||||
|
@ -287,8 +286,8 @@ The following XML snippet defines a list of commands:
|
|||
```
|
||||
|
||||
The user interface can use these values to render
|
||||
* a drop down and also represent the current state or
|
||||
* as push buttons to simply send a command to the ThingHandler.
|
||||
- a drop down and also represent the current state or
|
||||
- as push buttons to simply send a command to the ThingHandler.
|
||||
|
||||
The option labels can also be localized.
|
||||
|
||||
|
@ -479,7 +478,7 @@ To define such thing meta data the thing type definition provides the possibilit
|
|||
<property name="protocol">ZigBee</property>
|
||||
...
|
||||
</properties>
|
||||
...
|
||||
...
|
||||
</thing-type>
|
||||
```
|
||||
|
||||
|
@ -533,12 +532,12 @@ If a configuration parameter will be used, then its respective `parameter` shall
|
|||
...
|
||||
<representation-property>uniqueId</representation-property>
|
||||
...
|
||||
<config-description>
|
||||
<parameter name="uniqueId" type="text">
|
||||
<label>Unique Id</label>
|
||||
<description>The Unique Id for Representation Property</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
<config-description>
|
||||
<parameter name="uniqueId" type="text">
|
||||
<label>Unique Id</label>
|
||||
<description>The Unique Id for Representation Property</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
...
|
||||
</thing-type>
|
||||
```
|
||||
|
@ -549,10 +548,10 @@ The label and descriptions for things, channels and config descriptions should f
|
|||
The label should be short so that for most UIs it does not spread across multiple lines.
|
||||
Guideline is 2-3 words with up to 25 chars.
|
||||
Labels should be capitalized using the following rules:
|
||||
* Always capitalize the first and the last word.
|
||||
* Lowercase articles, coordinating conjunctions, and prepositions (`a, an, the, and, as, but, by, for, from, in, into, like, near, nor, of, onto, or, out, over, past, so, till, to, up, upon, with, yet`).
|
||||
* Capitalize all other words.
|
||||
* Brand- or product names that starts with a lowercase character can be written using their official spelling.
|
||||
- Always capitalize the first and the last word.
|
||||
- Lowercase articles, coordinating conjunctions, and prepositions (`a, an, the, and, as, but, by, for, from, in, into, like, near, nor, of, onto, or, out, over, past, so, till, to, up, upon, with, yet`).
|
||||
- Capitalize all other words.
|
||||
- Brand- or product names that starts with a lowercase character can be written using their official spelling.
|
||||
|
||||
The description can contain longer text to describe the thing in more detail.
|
||||
Limited use of HTML tags is permitted to enhance the description - if a long description is provided, the first line should be kept short, and a line break (```<br />```) placed at the end of the line to allow UIs to display a short description in limited space.
|
||||
|
@ -592,15 +591,14 @@ In this example, an auto update policy is defined for the channel type, but is o
|
|||
|
||||
The following policies are supported:
|
||||
|
||||
* **veto**: No automatic state update should be sent by the framework.
|
||||
- **veto**: No automatic state update should be sent by the framework.
|
||||
The thing handler will make sure it sends a state update and it can do it better than just converting the command to a state.
|
||||
* **default**: The binding does not care and the framework may do what it deems to be right.
|
||||
- **default**: The binding does not care and the framework may do what it deems to be right.
|
||||
The state update which the framework will send out normally will correspond the command state anyway.
|
||||
This is the default if no other policy is set explicitly.
|
||||
* **recommend**: An automatic state update should be sent by the framework because no updates are sent by the binding.
|
||||
- **recommend**: An automatic state update should be sent by the framework because no updates are sent by the binding.
|
||||
This usually is the case when devices don't expose their current state to the handler.
|
||||
|
||||
|
||||
## Bridges and Thing Descriptions
|
||||
|
||||
Every binding has to provide meta information about which bridges and/or *Thing*s it provides and how their relations to each other are structured.
|
||||
|
@ -612,7 +610,6 @@ The meta information of all bridges and *Thing*s is accessible through the `org.
|
|||
Bridge and *Thing* descriptions must be placed as XML file(s) (with the ending `.xml`) in the bundle's folder `/OH-INF/thing/`.
|
||||
The full Java API for bridge and *Thing* descriptions can be found in the Java package `org.openhab.core.thing.type`.
|
||||
|
||||
|
||||
### XML Structure for Thing Descriptions
|
||||
|
||||
```xml
|
||||
|
@ -847,8 +844,7 @@ The full Java API for bridge and *Thing* descriptions can be found in the Java p
|
|||
| channel.id | An identifier of the channel the bridge/Thing provides | mandatory |
|
||||
| channel.typeId | An identifier of the channel type definition the bridge/Thing provides | mandatory |
|
||||
|
||||
|
||||
The full XML schema for Thing type descriptions is specified in the <a href="https://openhab.org/schemas/thing-description-1.0.0.xsd">openHAB thing description XSD</a> file.
|
||||
The full XML schema for Thing type descriptions is specified in the [https://openhab.org/schemas/thing-description-1.0.0.xsd](https://openhab.org/schemas/thing-description-1.0.0.xsd) openHAB thing description XSD</a> file.
|
||||
|
||||
**Hints:**
|
||||
|
||||
|
|
|
@ -22,9 +22,10 @@ This section talks about some common buildsystem related topics and also some qu
|
|||
Generally all dependencies should be OSGi-bundles and available on JCenter.
|
||||
|
||||
### External dependency
|
||||
|
||||
In most cases they should be referenced in the project POM with scope `provided`:
|
||||
|
||||
```
|
||||
```xml
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>foo.bar</groupId>
|
||||
|
@ -45,13 +46,14 @@ There are two exceptions:
|
|||
Dependencies on other openHAB bundles should have the scope `provided`.
|
||||
To ensure that they are available at runtime they also need to be added to the `feature.xml`:
|
||||
|
||||
```
|
||||
```xml
|
||||
<bundle dependency="true">mvn:org.openhab.addons.bundles/org.openhab.binding.bluetooth/2.5.0-SNAPSHOT</bundle>
|
||||
```
|
||||
|
||||
### Internal dependency
|
||||
|
||||
In two cases libraries can be added to the `/lib` directory:
|
||||
|
||||
1. The bundle is not available for download
|
||||
2. The bundle is not an OSGi bundle but needs to be used for integration tests.
|
||||
Unlike Karaf, BND is not able to wrap bundles on its own.
|
||||
|
@ -61,9 +63,9 @@ You need add the library and export all needed packages manually.
|
|||
The build system automatically picks up all JAR files in `/lib` and embeds them in the new bundle.
|
||||
In this case they must not be added to the feature.
|
||||
|
||||
If the bundles manifest is not properly exporting all needed packages, you can import them manually by adding
|
||||
If the bundles manifest is not properly exporting all needed packages, you can import them manually by adding
|
||||
|
||||
```
|
||||
```xml
|
||||
<properties>
|
||||
<dep.noembedding>netty-common</dep.noembedding>
|
||||
</properties>
|
||||
|
@ -77,7 +79,7 @@ If you only depend on shared bundles you can also omit the exclusion statement a
|
|||
|
||||
If the imported packages need to be exposed to other bundles (e.g. case 2 above), this has to be done manually by adding
|
||||
|
||||
```
|
||||
```xml
|
||||
<properties>
|
||||
<bnd.exportpackage>foo.bar.*;version="1.0.0"</bnd.exportpackage>
|
||||
</properties>
|
||||
|
@ -109,7 +111,7 @@ Two cases need to be treated differently:
|
|||
In some cases a binding consists of several bundles (e.g. `mqtt`).
|
||||
The `feature.xml` of the sub-bundle (e.g. `mqtt.homie`) needs to add all bundles from the parent-bundle to make sure that the feature verification suceeds:
|
||||
|
||||
```
|
||||
```xml
|
||||
<feature>openhab-transport-mqtt</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.mqtt/${project.version}</bundle>
|
||||
```
|
||||
|
@ -117,7 +119,7 @@ The `feature.xml` of the sub-bundle (e.g. `mqtt.homie`) needs to add all bundles
|
|||
To make sure that all sub-bundles are installed together with the main-bundle, the `feature.xml` of the bundles needs to be excluded from the aggregation.
|
||||
Therefore an exclusion needs to be added to `features/openhab-addons/pom.xml` (starting from l. 47):
|
||||
|
||||
```
|
||||
```xml
|
||||
<exclude name="**/org.openhab.binding.mqtt*/**/feature.xml"/>
|
||||
```
|
||||
|
||||
|
|
|
@ -11,9 +11,9 @@ title: Contribution
|
|||
|
||||
The main parts of openHAB can be found in the following repositories:
|
||||
|
||||
* [openHAB Core](https://github.com/openhab/openhab-core): This repo contains the core framework bundles of which the openHAB runtime is constructed.
|
||||
* [openHAB Add-ons](https://github.com/openhab/openhab-addons): Add-ons (such as bindings, voice services, etc.) of openHAB can be found within this repository.
|
||||
* [openHAB Distro](https://github.com/openhab/openhab-distro): This repo contains all parts that are required for assembling the binary distribution of openHAB.
|
||||
- [openHAB Core](https://github.com/openhab/openhab-core): This repo contains the core framework bundles of which the openHAB runtime is constructed.
|
||||
- [openHAB Add-ons](https://github.com/openhab/openhab-addons): Add-ons (such as bindings, voice services, etc.) of openHAB can be found within this repository.
|
||||
- [openHAB Distro](https://github.com/openhab/openhab-distro): This repo contains all parts that are required for assembling the binary distribution of openHAB.
|
||||
|
||||
Besides those "main" repositories, there are a dozen further ones, which are not listed here in detail - just [check out the list](https://github.com/openhab) and you will find separate repos for openHAB Cloud, the Alexa skill, the Google Action, the Android and iOS apps, the Zigbee and ZWave bindings, HABPanel and HABot and many more.
|
||||
If you want to get involved with any of these, best check their respective README and CONTRIBUTING files in the root of the repos.
|
||||
|
@ -41,13 +41,13 @@ This gives other contributors a chance to point you in the right
|
|||
direction, give feedback on your design, and maybe point out if someone
|
||||
else is working on the same thing.
|
||||
|
||||
### Create Issues...
|
||||
### Create Issues
|
||||
|
||||
Any significant improvement should be documented as a GitHub
|
||||
issue in the [appropriate repository](#the-repositories) before anybody
|
||||
starts working on it.
|
||||
|
||||
### ...but Check for Existing Issues First!
|
||||
### ...but Check for Existing Issues First
|
||||
|
||||
Please take a moment to check that an issue doesn't already exist
|
||||
documenting your bug report or improvement proposal. If it does, it
|
||||
|
@ -101,8 +101,6 @@ or `Fixes #XXX`, which will automatically close the issue when merged.
|
|||
|
||||
openHAB maintainers use the [GitHub review feature](https://help.github.com/articles/about-pull-request-reviews/) to indicate acceptance.
|
||||
|
||||
|
||||
<a id="sign-your-work"></a>
|
||||
### Sign your Work
|
||||
|
||||
The sign-off is a simple line at the end of the explanation for the
|
||||
|
@ -111,7 +109,7 @@ pass it on as an open-source patch. The rules are pretty simple: if you
|
|||
can certify the below (from
|
||||
[developercertificate.org](https://developercertificate.org/)):
|
||||
|
||||
```
|
||||
```text
|
||||
Developer Certificate of Origin
|
||||
Version 1.1
|
||||
|
||||
|
@ -171,34 +169,36 @@ If your commit contains code from others as well, please ensure that they certif
|
|||
|
||||
There are several exceptions to the signing requirement. Currently these are:
|
||||
|
||||
* Your patch fixes spelling or grammar errors.
|
||||
* Your patch is a single line change to documentation.
|
||||
- Your patch fixes spelling or grammar errors.
|
||||
- Your patch is a single line change to documentation.
|
||||
|
||||
### How can I Become a Maintainer?
|
||||
|
||||
* Step 1: learn the component inside out
|
||||
* Step 2: make yourself useful by contributing code, bugfixes, support etc.
|
||||
* Step 3: volunteer [in the community] (https://community.openhab.org/c/development/misc) or in the appropriate GitHub project and have a [maintainer](governance.html#maintainers) [nominate you](governance.html#nominations).
|
||||
- Step 1: learn the component inside out
|
||||
- Step 2: make yourself useful by contributing code, bugfixes, support etc.
|
||||
- Step 3: volunteer [in the community] (<https://community.openhab.org/c/development/misc>) or in the appropriate GitHub project and have a [maintainer](governance.html#maintainers) [nominate you](governance.html#nominations).
|
||||
|
||||
Don't forget: being a maintainer is a time investment.
|
||||
Make sure you will have time to make yourself available.
|
||||
You don't have to be a maintainer to make a difference on the project!
|
||||
|
||||
### Contributing to the Documentation
|
||||
|
||||
Sharing your knowledge through documentation contributions is incredibly valuable for the community allowing everybody to benefit from your lessons learned.
|
||||
If you are not yet ready to contribute code don't let that stop you from contributing to the documentation.
|
||||
Documentation change requests are very easy.
|
||||
No need to file an issue.
|
||||
You don't even need to know Git.
|
||||
* Create a GitHub account and configure your full name in your profile.
|
||||
* Go to the documentation page that you want to update and click on "Edit this page on GitHub" at the bottom.
|
||||
* GitHub will bring up a web editor where you can enter your desired changes.
|
||||
* You can preview your changes under the "Preview changes" tab.
|
||||
* Add a title and optional description for your proposed change at the bottom of the editor.
|
||||
* The [sign off rules](#sign-your-work) described above do apply to documentation contributions as well.
|
||||
|
||||
- Create a GitHub account and configure your full name in your profile.
|
||||
- Go to the documentation page that you want to update and click on "Edit this page on GitHub" at the bottom.
|
||||
- GitHub will bring up a web editor where you can enter your desired changes.
|
||||
- You can preview your changes under the "Preview changes" tab.
|
||||
- Add a title and optional description for your proposed change at the bottom of the editor.
|
||||
- The [sign off rules](#sign-your-work) described above do apply to documentation contributions as well.
|
||||
Simply add an empty line and the sign off statement "Signed-off-by: Joe Smith \<joe.smith@email.com\>" at the end of your change description at the bottom of the editor.
|
||||
Note that as per the rules you have to provide your full name in the sign off and that full name has to match the name you configured in your GitHub profile for the DCO check to succeed.
|
||||
* Click the "Propose file change" button at the bottom of the editor, then click "Create pull request" on the next page, and then on the summary page click "Create pull request" one more time.
|
||||
- Click the "Propose file change" button at the bottom of the editor, then click "Create pull request" on the next page, and then on the summary page click "Create pull request" one more time.
|
||||
|
||||
If you prefer to use Git you can of course use the code contribution process for documentation contributions as well.
|
||||
|
||||
|
@ -208,20 +208,20 @@ We want to keep the openHAB community awesome, growing and collaborative. We
|
|||
need your help to keep it that way. To help with this we've come up with some
|
||||
general guidelines for the community as a whole:
|
||||
|
||||
* Be nice: Be courteous, respectful and polite to fellow community members: no
|
||||
- Be nice: Be courteous, respectful and polite to fellow community members: no
|
||||
regional, racial, gender, or other abuse will be tolerated. We like nice people
|
||||
way better than mean ones!
|
||||
|
||||
* Encourage diversity and participation: Make everyone in our community
|
||||
- Encourage diversity and participation: Make everyone in our community
|
||||
feel welcome, regardless of their background and the extent of their
|
||||
contributions, and do everything possible to encourage participation in
|
||||
our community.
|
||||
|
||||
* Keep it legal: Basically, don't get us in trouble. Share only content that
|
||||
- Keep it legal: Basically, don't get us in trouble. Share only content that
|
||||
you own, do not share private or sensitive information, and don't break the
|
||||
law.
|
||||
|
||||
* Stay on topic: Make sure that you are posting to the correct channel
|
||||
- Stay on topic: Make sure that you are posting to the correct channel
|
||||
and avoid off-topic discussions. Remember when you update an issue or
|
||||
respond to an email you are potentially sending to a large number of
|
||||
people. Please consider this before you update. Also remember that
|
||||
|
|
|
@ -11,6 +11,7 @@ license: Parts of this page have been derived from the EPLv2 licensed https://ww
|
|||
## Principles
|
||||
|
||||
The guiding principles for openHAB are the "open source rules of engagement", which comprise:
|
||||
|
||||
- Transparency
|
||||
- Openness
|
||||
- Meritocracy
|
||||
|
@ -40,6 +41,7 @@ The maintainers are the ones with write access to the repository and they are re
|
|||
### Responsibilities
|
||||
|
||||
Maintainers take care of the respective repository, i.e. they
|
||||
|
||||
- define coding guidelines
|
||||
- decide the architecture and features of the code
|
||||
- review PRs
|
||||
|
|
|
@ -6,6 +6,7 @@ title: Coding Guidelines
|
|||
{% include base.html %}
|
||||
|
||||
# Coding Guidelines
|
||||
|
||||
{:.no_toc}
|
||||
|
||||
The following guidelines apply to all (Java) code of the openHAB project.
|
||||
|
@ -18,14 +19,15 @@ To speed up the contribution process, we therefore advice to go through this che
|
|||
If you are just keen on binding development, you may skip this document first and come back later.
|
||||
|
||||
{::options toc_levels="2,3"/}
|
||||
* TOC
|
||||
|
||||
- TOC
|
||||
{:toc}
|
||||
|
||||
## A. Directory and File Layout
|
||||
|
||||
The structure of a binding follows the structure of a typical OSGi bundle project.
|
||||
|
||||
```
|
||||
```text
|
||||
|- doc Images and other assets used in the Readme.md
|
||||
|- src/main
|
||||
|---- feature
|
||||
|
@ -52,7 +54,7 @@ The structure of a binding follows the structure of a typical OSGi bundle projec
|
|||
|- README.md The file describing your binding
|
||||
```
|
||||
|
||||
* Every Java file must have a license header. You can run ```mvn license:format``` on the root of the repo to automatically add missing headers.
|
||||
- Every Java file must have a license header. You can run ```mvn license:format``` on the root of the repo to automatically add missing headers.
|
||||
|
||||
## B. Code formatting rules & style
|
||||
|
||||
|
@ -64,30 +66,30 @@ Rules are enforced as part of the build process using [Spotless Maven Plugin](ht
|
|||
To check if your code is following the code style run `mvn spotless:check`. If Maven prints `[INFO] Spotless check skipped` then run `mvn spotless:check -Dspotless.check.skip=false` instead as the check isn't mandatory yet.
|
||||
To reformat you code run `mvn spotless:apply`
|
||||
|
||||
Code styles files are located in here: https://github.com/openhab/static-code-analysis/tree/master/codestyle/src/main/resources
|
||||
Code styles files are located in here: <https://github.com/openhab/static-code-analysis/tree/master/codestyle/src/main/resources>
|
||||
|
||||
#### Java Code
|
||||
|
||||
The rules are defined using the Eclipse Java Formatter definitions. There are plugins available for several IDEs that support these definitons.
|
||||
|
||||
* Official [openHAB Eclipse IDE setup](ide/eclipse.html) is preconfigured
|
||||
* Eclipse standalone installation
|
||||
- Official [openHAB Eclipse IDE setup](ide/eclipse.html) is preconfigured
|
||||
- Eclipse standalone installation
|
||||
- You can manually import [openhab_codestyle.xml](https://raw.githubusercontent.com/openhab/static-code-analysis/master/codestyle/src/main/resources/openhab_codestyle.xml) via `Eclipse Preferences -> Java -> Code Style -> Formatter` and [openhab.importorder](https://raw.githubusercontent.com/openhab/static-code-analysis/master/codestyle/src/main/resources/openhab.importorder) via `Eclipse Preferences -> Java -> Code Style -> Organize Imports`
|
||||
* IntelliJ using plugin https://plugins.jetbrains.com/plugin/6546-eclipse-code-formatter
|
||||
- Same files as for the Eclipse standalone installation. Be sure to follow *all* the plugin configuration steps.
|
||||
- IntelliJ using plugin <https://plugins.jetbrains.com/plugin/6546-eclipse-code-formatter>
|
||||
- Same files as for the Eclipse standalone installation. Be sure to follow *all- the plugin configuration steps.
|
||||
|
||||
#### XML files
|
||||
|
||||
* Maven `pom.xml` files shall have 2 space indentation
|
||||
* Other `xml` files shall have 1 tab indentation
|
||||
* Line length shall be 120 characters
|
||||
- Maven `pom.xml` files shall have 2 space indentation
|
||||
- Other `xml` files shall have 1 tab indentation
|
||||
- Line length shall be 120 characters
|
||||
|
||||
The rules are defined at https://github.com/openhab/static-code-analysis/tree/master/codestyle/src/main/resources for the Eclipse WTP formatter, but will have to be manually entered into your IDE.
|
||||
The rules are defined at <https://github.com/openhab/static-code-analysis/tree/master/codestyle/src/main/resources> for the Eclipse WTP formatter, but will have to be manually entered into your IDE.
|
||||
|
||||
### Java Coding Style
|
||||
|
||||
* The [Java naming conventions](https://java.about.com/od/javasyntax/a/nameconventions.htm) should be used for source files.
|
||||
* Generics must be used where applicable. See example below:
|
||||
- The [Java naming conventions](https://java.about.com/od/javasyntax/a/nameconventions.htm) should be used for source files.
|
||||
- Generics must be used where applicable. See example below:
|
||||
|
||||
```java
|
||||
public static <T> boolean isEqual(GenericsType<T> g1, GenericsType<T> g2){
|
||||
|
@ -95,9 +97,9 @@ public static <T> boolean isEqual(GenericsType<T> g1, GenericsType<T> g2){
|
|||
}
|
||||
```
|
||||
|
||||
* Code MUST not show any warnings.
|
||||
- Code MUST not show any warnings.
|
||||
Warnings that cannot be circumvented should be suppressed by using the `@SuppressWarnings` annotation.
|
||||
* Your classes are generally organised within an internal package
|
||||
- Your classes are generally organised within an internal package
|
||||
|
||||
```java
|
||||
org.openhab.binding.coolbinding.internal
|
||||
|
@ -107,9 +109,9 @@ org.openhab.binding.coolbinding.internal.discovery
|
|||
|
||||
Remember that classes that are meant to be used by scripts or other bindings must be non internal.
|
||||
|
||||
* Every class, except data-transfer-objects (DTO), must be annotated with `@NonNullByDefault`.
|
||||
- Every class, except data-transfer-objects (DTO), must be annotated with `@NonNullByDefault`.
|
||||
For details see [Null annotation](#null-annotations).
|
||||
* OSGi Declarative Services annotations are to be used
|
||||
- OSGi Declarative Services annotations are to be used
|
||||
|
||||
```java
|
||||
@Component(service=MyCoolService.class)
|
||||
|
@ -123,10 +125,10 @@ public class MyCoolService {
|
|||
|
||||
JavaDoc is required to describe the purpose and usage of every:
|
||||
|
||||
* class,
|
||||
* interface,
|
||||
* enumeration (except inner classes and enums),
|
||||
* constant, field and method with visibility of default, protected or public.
|
||||
- class,
|
||||
- interface,
|
||||
- enumeration (except inner classes and enums),
|
||||
- constant, field and method with visibility of default, protected or public.
|
||||
|
||||
An @author tag is required within the JavaDoc for every author who made a substantial contribution to the file.
|
||||
New @author tags should be placed below the older ones.
|
||||
|
@ -135,9 +137,11 @@ Data-transfer-objects (DTOs map from Json/XML to Java classes) do not require Ja
|
|||
## D. Language Levels and Libraries
|
||||
|
||||
1. openHAB generally targets the long time supported Java 11 releases with the following restrictions:
|
||||
* To allow optimized runtimes, the set of Java packages to be used is further restricted to [Compact Profile 2](https://www.oracle.com/technetwork/java/embedded/resources/tech/compact-profiles-overview-2157132.html).
|
||||
2. The [OSGi Core Release 7](https://osgi.org/download/r7/osgi.core-7.0.0.pdf) with [OSGI Compendium Release 7](https://osgi.org/download/r7/osgi.cmpn-7.0.0.pdf) is targeted, and newer features should not be used.
|
||||
3. [slf4j](http://slf4j.org) is used for logging.
|
||||
|
||||
- To allow optimized runtimes, the set of Java packages to be used is further restricted to [Compact Profile 2](https://www.oracle.com/technetwork/java/embedded/resources/tech/compact-profiles-overview-2157132.html).
|
||||
|
||||
1. The [OSGi Core Release 7](https://osgi.org/download/r7/osgi.core-7.0.0.pdf) with [OSGI Compendium Release 7](https://osgi.org/download/r7/osgi.cmpn-7.0.0.pdf) is targeted, and newer features should not be used.
|
||||
1. [slf4j](http://slf4j.org) is used for logging.
|
||||
|
||||
You might also have the need to use other libraries for specific use cases like XML processing, networking etc.
|
||||
See [Default libraries](#default-libraries) for more details.
|
||||
|
@ -162,7 +166,7 @@ The logger that is used allows logging at multiple severity levels (trace, info,
|
|||
Most of the time, a level of `warn` or `debug` will be used.
|
||||
Please remember that every logging statement adds to code size and runtime cost.
|
||||
|
||||
* Loggers should be [non-static](http://slf4j.org/faq.html#declared_static), `final` when ever possible and have the name `logger`.
|
||||
- Loggers should be [non-static](http://slf4j.org/faq.html#declared_static), `final` when ever possible and have the name `logger`.
|
||||
|
||||
```java
|
||||
class MyCoolClass {
|
||||
|
@ -170,7 +174,7 @@ class MyCoolClass {
|
|||
}
|
||||
```
|
||||
|
||||
* Parametrized logging must be used (instead of string concatenation).
|
||||
- Parametrized logging must be used (instead of string concatenation).
|
||||
|
||||
```java
|
||||
void myFun() {
|
||||
|
@ -180,7 +184,7 @@ void myFun() {
|
|||
}
|
||||
```
|
||||
|
||||
* Exceptions with stacktraces in the log are considered to be bugs in your binding that should be reported and fixed.
|
||||
- Exceptions with stacktraces in the log are considered to be bugs in your binding that should be reported and fixed.
|
||||
If you add an exception as a last parameter to the logging, the stack trace will be printed.
|
||||
Configuration errors by users should only print log messages about what's wrong. In that case you would use `e.getMessage()`.
|
||||
|
||||
|
@ -194,7 +198,7 @@ void myFun() {
|
|||
}
|
||||
```
|
||||
|
||||
* Logging is not a replacement for using the debugger.
|
||||
- Logging is not a replacement for using the debugger.
|
||||
|
||||
```java
|
||||
void myFun() {
|
||||
|
@ -204,7 +208,7 @@ void myFun() {
|
|||
}
|
||||
```
|
||||
|
||||
* Logging is not a replacement to use respective `update*` methods of the framework
|
||||
- Logging is not a replacement to use respective `update*` methods of the framework
|
||||
|
||||
```java
|
||||
void myFun() {
|
||||
|
@ -218,23 +222,23 @@ As every bundle is only one out of many, logging should be done very scarce.
|
|||
It should be up to the user to increase the logging level for specific bundles, packages or classes if necessary.
|
||||
This means in detail:
|
||||
|
||||
* `error` logging should only be used
|
||||
- `error` logging should only be used
|
||||
- to inform the user that something is tremendously wrong in the setup, the system cannot function normally anymore, and there is a need for immediate action.
|
||||
- in case some code fails irrecoverably and the user should report it as a severe bug.
|
||||
|
||||
* `warn` logging should only be used
|
||||
- `warn` logging should only be used
|
||||
- to inform the user that something seems to be wrong in the overall setup, but the system can nonetheless function as normal,
|
||||
- in recoverable situations when a section of code that is not accessed under normal operating conditions is reached.
|
||||
|
||||
* `info` logging should be used sparsely.
|
||||
- `info` logging should be used sparsely.
|
||||
e.g. a newly started component or a user file that has been loaded.
|
||||
|
||||
* `debug` logging should be used for detailed logging
|
||||
- `debug` logging should be used for detailed logging
|
||||
- to give the user debug information in cases of unexpected behavior.
|
||||
- to log exceptions in case of temporary problems, like connection problems.
|
||||
In case of such exceptions this should be reflected in an updated state of the binding.
|
||||
|
||||
* `trace` logging should be used for verbose debug logging.
|
||||
- `trace` logging should be used for verbose debug logging.
|
||||
For example printing output values that can be large, but can help when debugging changed external apis.
|
||||
|
||||
In general bindings should NOT log to error/warn if e.g. connections are dropped -
|
||||
|
@ -322,22 +326,22 @@ In order to not have every binding use a different library, the following packag
|
|||
|
||||
For XML Processing
|
||||
|
||||
* com.thoughtworks.xstream
|
||||
* com.thoughtworks.xstream.annotations
|
||||
* com.thoughtworks.xstream.converters
|
||||
* com.thoughtworks.xstream.io
|
||||
* com.thoughtworks.xstream.io.xml
|
||||
- com.thoughtworks.xstream
|
||||
- com.thoughtworks.xstream.annotations
|
||||
- com.thoughtworks.xstream.converters
|
||||
- com.thoughtworks.xstream.io
|
||||
- com.thoughtworks.xstream.io.xml
|
||||
|
||||
For JSON Processing
|
||||
|
||||
* com.google.gson.*
|
||||
- com.google.gson.*
|
||||
|
||||
For HTTP Operations
|
||||
|
||||
* org.eclipse.jetty.client.*
|
||||
* org.eclipse.jetty.client.api.*
|
||||
* org.eclipse.jetty.http.*
|
||||
* org.eclipse.jetty.util.*
|
||||
- org.eclipse.jetty.client.*
|
||||
- org.eclipse.jetty.client.api.*
|
||||
- org.eclipse.jetty.http.*
|
||||
- org.eclipse.jetty.util.*
|
||||
|
||||
::: tip Note
|
||||
HttpClient instances should be obtained by the handler factory through the HttpClientFactory service and unless there are specific configuration requirements, the shared instance should be used.
|
||||
|
@ -345,8 +349,8 @@ HttpClient instances should be obtained by the handler factory through the HttpC
|
|||
|
||||
For Web Socket Operations
|
||||
|
||||
* org.eclipse.jetty.websocket.client
|
||||
* org.eclipse.jetty.websocket.api
|
||||
- org.eclipse.jetty.websocket.client
|
||||
- org.eclipse.jetty.websocket.api
|
||||
|
||||
::: tip Note
|
||||
WebSocketClient instances should be obtained by the handler factory through the WebSocketClientFactory service and unless there are specific configuration requirements, the shared instance should be used.
|
||||
|
|
|
@ -10,7 +10,7 @@ To make development easier an out-of-the-box setup is available that completely
|
|||
This guide describes the steps to setup Eclipse and how to run and debug an add-on in Eclipse.
|
||||
|
||||
::: tip Existing Eclipse Installations
|
||||
If you already have Eclipse installed it is recommended to perform a separate Eclipse install for OpenHAB to avoid overriding your existing Eclipse configuration.
|
||||
If you already have Eclipse installed it is recommended to perform a separate Eclipse install for OpenHAB to avoid overriding your existing Eclipse configuration.
|
||||
:::
|
||||
|
||||
## Eclipse IDE Setup
|
||||
|
@ -63,12 +63,10 @@ If you already have Eclipse installed it is recommended to perform a separate Ec
|
|||
- `Installation folder name`: This is the directory in the root install folder everything will be installed in.
|
||||
- `GitHub user ID`: This is your GitHub user name used to configure the cloned Git projects.
|
||||
|
||||
|
||||
1. Click `Next>` and `Finish` to start installation.
|
||||
|
||||
During install accept licence agreement, "Unsigned Content" for Bndtools, and Eclipse Foundation certificates when requested to complete IDE installation.
|
||||
|
||||
|
||||
1. At this point the Eclipse installer is finished and the Eclipse IDE is automatically launched to continue the installation process.
|
||||
|
||||
::: warning Attention
|
||||
|
@ -89,8 +87,8 @@ For other libraries supported out-of-the-box check the [Default Libraries](../gu
|
|||
|
||||
## Working with Add-ons
|
||||
|
||||
To easily run, modify and debug an add-on the `openHAB Development` setup installs and imports a demo project that contains a complete openHAB environment to run and debug an add-on.
|
||||
This mechanism replaces the add-on installation process via the PaperUI that you would use outside the IDE.
|
||||
To easily run, modify and debug an add-on the `openHAB Development` setup installs and imports a demo project that contains a complete openHAB environment to run and debug an add-on.
|
||||
This mechanism replaces the add-on installation process via the PaperUI that you would use outside the IDE.
|
||||
|
||||
### Running Add-ons
|
||||
|
||||
|
@ -98,7 +96,7 @@ Under `Infrastructure` you will find the project `org.openhab.demo.app`.
|
|||
This project contains the full configuration to run OpenHAB.
|
||||
The following files are of interest for the execution environment:
|
||||
|
||||
```
|
||||
```text
|
||||
|- org.openhab.demo.app
|
||||
|--- runtime
|
||||
|------- conf Here you configure the manual text files
|
||||
|
@ -138,17 +136,17 @@ Here is an example for the `astro` binding:
|
|||
|
||||
1. Save and click "Resolve": a window with the list of resolved bundles will be shown.
|
||||
Click `Finish` and save the file.
|
||||
|
||||
|
||||
::: tip
|
||||
Watch out - it's easy to miss saving the `app.bndrun` file.
|
||||
If you see the little asterisk next to `app` in the `app` tab you haven't yet saved.
|
||||
Watch out - it's easy to miss saving the `app.bndrun` file.
|
||||
If you see the little asterisk next to `app` in the `app` tab you haven't yet saved.
|
||||
:::
|
||||
|
||||
Now the IDE is ready to start openHAB with a minimum set of the openHAB core bindings, UIs and the add-ons you configured.
|
||||
|
||||
1. Start openHAB from the IDE by clicking "Run OSGi" (upper right of the `app.bndrun` window).
|
||||
|
||||
1. You can check that openHAB is running with your browser by going to: http://localhost:8080/paperui/ (the last `/` is important!)
|
||||
1. You can check that openHAB is running with your browser by going to: `http://localhost:8080/paperui/` (the last `/` is important!)
|
||||
|
||||
1. You can check log output in the `Console` tab at the bottom.
|
||||
|
||||
|
@ -160,27 +158,27 @@ View all the above steps in a single animation:
|
|||
|
||||
### Modifying and Debugging Add-ons
|
||||
|
||||
If you don't just want to run an add-on, but also want to modify and debug it you need to install sources for the add-on and build them locally.
|
||||
If you don't just want to run an add-on, but also want to modify and debug it you need to install sources for the add-on and build them locally.
|
||||
|
||||
1. Install Sources
|
||||
|
||||
Sources are installed by cloning the [openHAB Add-ons](https://github.com/openhab/openhab-addons/) repository.
|
||||
Sources are installed by cloning the [openHAB Add-ons](https://github.com/openhab/openhab-addons/) repository.
|
||||
If you select `openHAB Add-ons` during installation the installer automatically clones the [openHAB Add-ons](https://github.com/openhab/openhab-addons/) repository into `git\openhab-addons` under your installation folder.
|
||||
|
||||
If you didn't install `openHAB Add-ons` you can manually clone the [openHAB Add-ons](https://github.com/openhab/openhab-addons/) repository by executing `git clone https://github.com/openhab/openhab-addons.git` in the `git` folder under your installation folder.
|
||||
If you didn't install `openHAB Add-ons` you can manually clone the [openHAB Add-ons](https://github.com/openhab/openhab-addons/) repository by executing `git clone https://github.com/openhab/openhab-addons.git` in the `git` folder under your installation folder.
|
||||
|
||||
You can now modify add-on sources as needed.
|
||||
|
||||
1. Build Sources
|
||||
|
||||
Add the add-on as an Eclipse project so that Eclipse will build it automatically.
|
||||
Import the add-on project via `File > Import... > Maven > Existing Maven Projects`.
|
||||
Specify your add-on's source root folder (e.g. `git\openhab-addons\bundles\org.openhab.binding.astro` under the installation folder) as the root folder in the wizard.
|
||||
Add the add-on as an Eclipse project so that Eclipse will build it automatically.
|
||||
Import the add-on project via `File > Import... > Maven > Existing Maven Projects`.
|
||||
Specify your add-on's source root folder (e.g. `git\openhab-addons\bundles\org.openhab.binding.astro` under the installation folder) as the root folder in the wizard.
|
||||
|
||||
1. Start a Debug Session
|
||||
|
||||
Simply start your debug session by clicking "Debug OSGi" (upper right of the `app.bndrun` window).
|
||||
You can now use breakpoints and all other Eclipse debug tools.
|
||||
Simply start your debug session by clicking "Debug OSGi" (upper right of the `app.bndrun` window).
|
||||
You can now use breakpoints and all other Eclipse debug tools.
|
||||
|
||||
::: tip Where do add-on jar files come from?
|
||||
If you just run an add-on following the above steps then the required add-on jar files are retrieved through your Maven repository folder `.m2/repository` (e.g. `.m2\repository\org\openhab\addons\bundles\org.openhab.binding.astro`).
|
||||
|
@ -190,9 +188,9 @@ If you imported your add-on as a project then the jar file is no longer retrieve
|
|||
### Using New Bindings
|
||||
|
||||
If you want to develop a new binding read about the [Skeleton Script](../#develop-a-new-binding) to generate the base for your binding and create all required files.
|
||||
Then follow the above steps to build your sources and to configure the demo app to run your binding.
|
||||
Then follow the above steps to build your sources and to configure the demo app to run your binding.
|
||||
|
||||
## Updating OpenHAB
|
||||
|
||||
You can update the OpenHAB version you are running in the IDE at any time simply by updating your git repos under your install folder.
|
||||
For example to update to the latest version run `git checkout` in each repo folder under your `git` folder in the installation folder.
|
||||
You can update the OpenHAB version you are running in the IDE at any time simply by updating your git repos under your install folder.
|
||||
For example to update to the latest version run `git checkout` in each repo folder under your `git` folder in the installation folder.
|
||||
|
|
|
@ -6,15 +6,18 @@ title: IntelliJ
|
|||
# IntelliJ IDE
|
||||
|
||||
## Prerequisities
|
||||
- git, Maven, IntelliJ and Java 11 are installed
|
||||
|
||||
- git, Maven, IntelliJ and Java 11 are installed
|
||||
|
||||
## Install OpenHAB distribution
|
||||
|
||||
1. Install the official [openHAB distribution](https://www.openhab.org/download/)
|
||||
1. Start the distribution **in debug mode** (use `./start_debug.sh` instead of `./start.sh` in step 4)
|
||||
|
||||
This article refers to the directory where you installed the distribution as `<DISTRO_DIR>`.
|
||||
|
||||
## Build the addons repostory
|
||||
|
||||
1. fork and clone the [openhab addons repository](https://www.github.com/openhab/openhab-addons) into a new directory (Reference `<ADDON_DIR>` from now on for this arcticle)
|
||||
- `git clone https://github.com/<yourgitusername>/openhab-addons` (replace git user name accordingly)
|
||||
1. open IntelliJ and create a new Project from existing sources (File | New | Project from existing sources) and pick `<ADDON_DIR>`/pom.xml
|
||||
|
@ -25,6 +28,7 @@ This article refers to the directory where you installed the distribution as `<D
|
|||
- when the Maven project finished, you should find the freshly built addon JAR in the target directory
|
||||
|
||||
## Debug your addon
|
||||
|
||||
1. copy the addon JAR to Openhab distribution created before
|
||||
- `cp target/<ADDON_NAME>.jar <DISTRO_DIR>/addons`
|
||||
1. The running instance of the openhab distribution should pick up your new addon & start it
|
||||
|
|
|
@ -11,24 +11,24 @@ The following shows the steps for building a bundle using Visual Studio Code (VS
|
|||
|
||||
The following steps will only need to be done once to setup both VSCode and your environment.
|
||||
|
||||
1. Install Java Extension Pack for VSCode (https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack)
|
||||
|
||||
1. Clone the addons (https://github.com/openhab/openhab-addons.git or preferably your own fork) to %BASE%\openhab-addons
|
||||
|
||||
3. On Windows, VSCode should be configured to use powershell instead of the classic command line.
|
||||
1. Install Java Extension Pack for VSCode (<https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-pack>)
|
||||
|
||||
1. Clone the addons (<https://github.com/openhab/openhab-addons.git> or preferably your own fork) to %BASE%\openhab-addons
|
||||
|
||||
1. On Windows, VSCode should be configured to use powershell instead of the classic command line.
|
||||
If not configured already, add the following to the VSCode settings:
|
||||
|
||||
|
||||
```"terminal.integrated.automationShell.windows": "C:\\Windows\\sysnative\\WindowsPowerShell\\v1.0\\powershell.exe"```
|
||||
|
||||
Either globally define the options via the global ```settings.json```. You can also define them local to a specific bundle by putting those lines in the ```.vscode/settings.json``` file in the bundle (similar to ```tasks.json```/```launch.json``` below).
|
||||
|
||||
1. If you want to setup openHAB code formatting guidelines, add the following to the VSCode settings:
|
||||
|
||||
|
||||
![define .vscode](images/ide_setup_vscode_settings.png)
|
||||
|
||||
Either globally define the formatting options via ```Files->Preferences->Settings->Extendions->Java configuration``` (or in the global ```settings.json```). You can also define them local to a specific bundle by putting those lines in the ```.vscode/settings.json``` file in the bundle (similar to ```tasks.json```/```launch.json``` below).
|
||||
|
||||
Download [settings.json](https://raw.githubusercontent.com/openhab/openhab-docs/master/developers/ide/examples/vscode/settings.json) for the recommended settings (or simply wish to copy the URLs in the above image).
|
||||
Download [settings.json](https://raw.githubusercontent.com/openhab/openhab-docs/master/developers/ide/examples/vscode/settings.json) for the recommended settings (or simply wish to copy the URLs in the above image).
|
||||
|
||||
## Steps for each Bundle
|
||||
|
||||
|
@ -38,36 +38,36 @@ The following steps will show you how to setup a specific bundle for development
|
|||
1. Open console to the bundle location (example: `%BASE%\openhab-addons\bundles\org.openhab.binding.russound`)
|
||||
2. `mvn clean install -DskipChecks` in the console to build the bundle
|
||||
3. Should produce a jar file in the 'target' directory of the bundle(example: `%BASE%\openhab-addons\bundles\org.openhab.binding.russound\target\org.openhab.binding.russound-2.5.0-SNAPSHOT.jar`)
|
||||
|
||||
|
||||
2. Open VSCode and then open the folder of the bundle. From VSCode - use `File->Open Folder->choose bundle directory` (example: `%BASE%\openhab-addons\bundles\org.openhab.binding.russound`)
|
||||
|
||||
|
||||
3. Create a ".vscode" directory under the bundle (example: `%BASE%\openhab-addons\bundles\org.openhab.binding.russound\.vscode`)
|
||||
|
||||
|
||||
![define .vscode](images/ide_setup_vscode_folder.png)
|
||||
|
||||
4. Download [tasks.json](https://raw.githubusercontent.com/openhab/openhab-docs/master/developers/ide/examples/vscode/tasks.json) to the .vscode directory (example: `%BASE%\openhab-addons\bundles\org.openhab.binding.russound\.vscode\tasks.json`)
|
||||
|
||||
|
||||
![define tasks.json](./images/ide_setup_vscode_folder_tasks.png)
|
||||
|
||||
|
||||
5. Edit tasks.json and ...
|
||||
|
||||
|
||||
![tasks.json changes](./images/ide_setup_vscode_tasks.png)
|
||||
|
||||
1. Set `openhab_*` to the directories for your openHAB installation
|
||||
1. Set `openhab_*` to the directories for your openHAB installation
|
||||
2. Set `dist` to the name of the JAR file maven is producing in the target directory
|
||||
3. Save and close tasks.json
|
||||
|
||||
6. Stop any openHAB instance (if it's running).
|
||||
|
||||
7. Start the openHAB instance with the debug option - `start.bat debug` from a console in the openHAB home directory. You should see the following line printed somewhere in the karaf console:
|
||||
`Listening for transport dt_socket at address: xxxx` (where xxxx should be 5005)
|
||||
|
||||
8. Download [launch.json](https://raw.githubusercontent.com/openhab/openhab-docs/master/developers/ide/examples/vscode/launch.json) to the .vscode directory (example: `%BASE%\openhab-addons\bundles\org.openhab.binding.russound\.vscode\launch.json`)
|
||||
6. Stop any openHAB instance (if it's running).
|
||||
|
||||
7. Start the openHAB instance with the debug option - `start.bat debug` from a console in the openHAB home directory. You should see the following line printed somewhere in the karaf console:
|
||||
`Listening for transport dt_socket at address: xxxx` (where xxxx should be 5005)
|
||||
|
||||
8. Download [launch.json](https://raw.githubusercontent.com/openhab/openhab-docs/master/developers/ide/examples/vscode/launch.json) to the .vscode directory (example: `%BASE%\openhab-addons\bundles\org.openhab.binding.russound\.vscode\launch.json`)
|
||||
|
||||
![define launch.json](./images/ide_setup_vscode_folder_launch.png)
|
||||
|
||||
9. Edit launch.json and ...
|
||||
|
||||
9. Edit launch.json and ...
|
||||
|
||||
![launch.json changes](./images/ide_setup_vscode_launch.png)
|
||||
|
||||
1. Set the `port` to xxxx (from step 7). This can be skipped if xxxx was 5005 from step 7.
|
||||
|
@ -75,7 +75,7 @@ The following steps will show you how to setup a specific bundle for development
|
|||
3. Save and close launch.json
|
||||
|
||||
10. Verify that VSCode can build the system and connect to a debug instance of openHAB:
|
||||
|
||||
|
||||
1. Shutdown any instances of openHAB
|
||||
2. Press `CTRL-SHIFT-P -> Tasks: Run Task -> Start openHAB (Debug)` to start an openHAB instance in debug mode. You should see openHAB startup in a new VSCode terminal.
|
||||
3. Press F5 (or bring up debug in VSCode and choose the "Debug (Attach) - openHAB" configuration) and the following should occur in the VSCode terminal
|
||||
|
@ -83,7 +83,7 @@ The following steps will show you how to setup a specific bundle for development
|
|||
1. The maven compile occuring (successfully)
|
||||
2. The resulting JAR is copied to the openHAB addons directory (`openhab_addons`)
|
||||
3. Connecting to the openHAB instance (the debug call stack should show a bunch of openHAB type threads running)
|
||||
|
||||
|
||||
You can now make changes, set breakpoints, etc.
|
||||
|
||||
## Notes
|
||||
|
@ -91,7 +91,7 @@ You can now make changes, set breakpoints, etc.
|
|||
1. May take openHAB a few seconds to realize there is a new bundle and to reinitilize it after it's been copied. Be a little bit patient.
|
||||
2. You must run the `mvn Compile (Online)` task atleast once to allow the offline compile to occur. You should use the `mvn Compile (Offline)` task for most of your development as it's quicker since it uses the cache files. When you are ready to commit (or release a test bundle) - you should run the `mvn Compile (Release)` task to include code checks (and resolve them).
|
||||
3. Win10+ allows forward slashes as part of its path. If you use backward slashes instead - you will need to double up on them since tasks.json uses a backward slash as a delimiter. Example: `c:\\\\openhab`
|
||||
|
||||
|
||||
## Tasks
|
||||
|
||||
The [tasks.json](examples/vscode/tasks.json) defines the following tasks that you may use withing VSCode (`CTRL-SHIFT-P > Tasks: Run Task`):
|
||||
|
@ -105,7 +105,7 @@ The [tasks.json](examples/vscode/tasks.json) defines the following tasks that yo
|
|||
7. **Build** - this is an alias for `Copy Distribution to Addons` task.
|
||||
8. **Tail events.log** - this will tail the events.log in a new terminal.
|
||||
9. **Tail openhab.log** - this will tail the openhab.log in a new terminal.
|
||||
|
||||
|
||||
## Additional References
|
||||
|
||||
1. [VSCode with Java](https://code.visualstudio.com/docs/languages/java)
|
||||
|
|
|
@ -22,16 +22,16 @@ The different guides of this chapter assume that you are somewhat familiar with
|
|||
|
||||
openHAB allows you to build upon the following concepts:
|
||||
|
||||
* **Bindings**: A binding connects to external services or devices.
|
||||
* **Automation engine module**: A trigger, condition, or action that can be used in automation rules (or scripts).
|
||||
* **Transformation / Profiles**: Can be used to transform a *Thing Channel* value before it is assigned to an *Item*.
|
||||
* **An IO service**: Exposes openHAB internals via a defined interface (for example the REST interface, HomeKit or Hue Emulation Service).
|
||||
* **A Persistence service**: Persist item state updates and/or changes and allows them to be retrieved for specific points in time.
|
||||
* **Natural language processing skill**:
|
||||
- **Bindings**: A binding connects to external services or devices.
|
||||
- **Automation engine module**: A trigger, condition, or action that can be used in automation rules (or scripts).
|
||||
- **Transformation / Profiles**: Can be used to transform a *Thing Channel*- value before it is assigned to an *Item*.
|
||||
- **An IO service**: Exposes openHAB internals via a defined interface (for example the REST interface, HomeKit or Hue Emulation Service).
|
||||
- **A Persistence service**: Persist item state updates and/or changes and allows them to be retrieved for specific points in time.
|
||||
- **Natural language processing skill**:
|
||||
Executes something depending on the understood Intents and returns something back to the user.
|
||||
* **Audio sinks/sources**:
|
||||
- **Audio sinks/sources**:
|
||||
Control where audio can be played or implement audio sources.
|
||||
* and many more (not covered yet).
|
||||
- and many more (not covered yet).
|
||||
|
||||
First think about what you want to achieve! Check our [community forum](https://community.openhab.org)
|
||||
and discuss your concept.
|
||||
|
@ -84,12 +84,14 @@ This script is specific for binding addons. Follow these steps to generate your
|
|||
1. From the command line in `openhab-addons/bundles` directory to create a skeleton of a new binding `mynewbinding` run:
|
||||
|
||||
On Linux:
|
||||
```
|
||||
|
||||
```bash
|
||||
./create_openhab_binding_skeleton.sh MyNewBinding "<Author>" <GitHubUsername>
|
||||
```
|
||||
|
||||
On Windows:
|
||||
```
|
||||
|
||||
```bash
|
||||
create_openhab_binding_skeleton.cmd MyNewBinding "<Author>" <GitHubUsername>
|
||||
```
|
||||
|
||||
|
@ -98,19 +100,22 @@ This script is specific for binding addons. Follow these steps to generate your
|
|||
1. Accept with `Y` when the skeleton configuration asks for it.
|
||||
|
||||
1. From `openhab-addons` root you can build only your binding with maven using the `-pl` option:
|
||||
```
|
||||
|
||||
```bash
|
||||
mvn clean install -pl :org.openhab.binding.mynewbinding
|
||||
```
|
||||
|
||||
Where `mynewbinding` is the name of your new binding.
|
||||
Some additional maven options that may help:
|
||||
* `-U`: Forces all dependencies to be downloaded again.
|
||||
* `-am`: Builds all projects in openhab-addons your project dependends on.
|
||||
* `-o`: Won't update any dependencies.
|
||||
* `-DskipChecks`: Skips the static analysis checks
|
||||
* `-DskipTests`: Skips the unit tests
|
||||
- `-U`: Forces all dependencies to be downloaded again.
|
||||
- `-am`: Builds all projects in openhab-addons your project dependends on.
|
||||
- `-o`: Won't update any dependencies.
|
||||
- `-DskipChecks`: Skips the static analysis checks
|
||||
- `-DskipTests`: Skips the unit tests
|
||||
|
||||
1. To start your new binding it's a good practise to commit your code on a new git branch:
|
||||
```
|
||||
|
||||
```bash
|
||||
git checkout -b <mynewbranch>
|
||||
```
|
||||
|
||||
|
|
|
@ -6,12 +6,14 @@ title: Automation Modules
|
|||
{% include base.html %}
|
||||
|
||||
# Developing Automation Modules
|
||||
|
||||
{:.no_toc}
|
||||
|
||||
In this section you will be guided through developing *Module Types* and corresponding *Module Handlers* for the automation engine of openHAB.
|
||||
|
||||
{::options toc_levels="2,3"/}
|
||||
* TOC
|
||||
|
||||
- TOC
|
||||
{:toc}
|
||||
|
||||
## Module Types and Module Handlers
|
||||
|
@ -178,9 +180,9 @@ The Condition that we are going to implement in the Condition Handler latter on
|
|||
Notice that our output is of type "State" instead of a fully qualified class name like `java.lang.String`.
|
||||
The following openHAB classes have short forms:
|
||||
|
||||
* "State" (an *Item* state)
|
||||
* "Event" (an openHAB event from the event bus)
|
||||
* "Command" (a command targeting an *Item*)
|
||||
- "State" (an *Item* state)
|
||||
- "Event" (an openHAB event from the event bus)
|
||||
- "Command" (a command targeting an *Item*)
|
||||
|
||||
And now let's have a look at the Action type.
|
||||
|
||||
|
@ -237,21 +239,21 @@ A module type file can contain one or multiple type descriptions.
|
|||
For our scenario we go with one file:
|
||||
|
||||
```json
|
||||
{
|
||||
{
|
||||
"triggers":[
|
||||
{
|
||||
{
|
||||
"uid":"TemperatureTriggerType",
|
||||
"label":"Temperature Trigger",
|
||||
"description":"This triggers when the temperature has reached a certain value",
|
||||
"configDescriptions":[
|
||||
{
|
||||
"configDescriptions":[
|
||||
{
|
||||
"name":"temperature",
|
||||
"type":"INTEGER",
|
||||
"label":"Temperature",
|
||||
"description":"Trigger temperature",
|
||||
"required":true
|
||||
},
|
||||
{
|
||||
{
|
||||
"name":"operator",
|
||||
"type":"TEXT",
|
||||
"label":"Operator",
|
||||
|
@ -260,8 +262,8 @@ For our scenario we go with one file:
|
|||
"default": "above"
|
||||
}
|
||||
],
|
||||
"outputs":[
|
||||
{
|
||||
"outputs":[
|
||||
{
|
||||
"name":"temperature",
|
||||
"type":"java.lang.Integer",
|
||||
"label":"Current Temperature",
|
||||
|
@ -270,13 +272,13 @@ For our scenario we go with one file:
|
|||
]
|
||||
}
|
||||
],
|
||||
"conditions":[
|
||||
{
|
||||
"conditions":[
|
||||
{
|
||||
"uid":"PresenceConditionType",
|
||||
"label":"Presence Condition",
|
||||
"description":"This condition is satisfied when the configure presence item is in ON state",
|
||||
"configDescriptions":[
|
||||
{
|
||||
"configDescriptions":[
|
||||
{
|
||||
"name":"presence",
|
||||
"type":"TEXT",
|
||||
"label":"Presence item",
|
||||
|
@ -284,8 +286,8 @@ For our scenario we go with one file:
|
|||
"required":true
|
||||
}
|
||||
],
|
||||
"outputs":[
|
||||
{
|
||||
"outputs":[
|
||||
{
|
||||
"name":"presence",
|
||||
"type":"State",
|
||||
"label":"Output value",
|
||||
|
@ -294,20 +296,20 @@ For our scenario we go with one file:
|
|||
]
|
||||
}
|
||||
],
|
||||
"actions":[
|
||||
{
|
||||
"actions":[
|
||||
{
|
||||
"uid":"AirConditionerActionType",
|
||||
"label":"Switch an air conditioner",
|
||||
"description":"Control an air conditioner. Depending on the configuration and inputs it is switched into different power levels",
|
||||
"configDescriptions":[
|
||||
{
|
||||
"configDescriptions":[
|
||||
{
|
||||
"name":"level1_min_temp",
|
||||
"type":"INTEGER",
|
||||
"label":"Temperature for level 1",
|
||||
"description":"Level 1 on the given temperature in celsius",
|
||||
"required":true
|
||||
},
|
||||
{
|
||||
{
|
||||
"name":"level2_min_temp",
|
||||
"type":"INTEGER",
|
||||
"label":"Temperature for level 2",
|
||||
|
@ -315,8 +317,8 @@ For our scenario we go with one file:
|
|||
"required":true
|
||||
}
|
||||
],
|
||||
"inputs":[
|
||||
{
|
||||
"inputs":[
|
||||
{
|
||||
"name":"temperature",
|
||||
"type":"java.lang.Integer",
|
||||
"label":"Current Temperature",
|
||||
|
@ -334,9 +336,9 @@ You now have semantically described your modules.
|
|||
|
||||
The pieces of code that actually
|
||||
|
||||
* trigger, in case of Trigger types,
|
||||
* decide on condition satisfaction for Condition types or
|
||||
* execute something in case of Action types
|
||||
- trigger, in case of Trigger types,
|
||||
- decide on condition satisfaction for Condition types or
|
||||
- execute something in case of Action types
|
||||
|
||||
are called *Module handlers*.
|
||||
|
||||
|
@ -408,7 +410,7 @@ public class TemperatureTriggerHandler extends BaseTriggerModuleHandler
|
|||
|
||||
String tempOp = (String) context.get(TemperatureTriggerType.CONFIG_OPERATOR);
|
||||
onAbove = (tempOp != null && "below".equals(tempOp)) ? false : true;
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Setup your triggering stuff in here
|
||||
|
@ -426,7 +428,7 @@ public class TemperatureTriggerHandler extends BaseTriggerModuleHandler
|
|||
|
||||
// Event from our imaginary temperature device. Triggers connected rules if temp is
|
||||
// over the configured threshold.
|
||||
@Override
|
||||
@Override
|
||||
public void tempChangedOnImaginaryDevice(int tempInCelsius) {
|
||||
if (
|
||||
(tempInCelsius>temperature && onAbove) ||
|
||||
|
@ -438,7 +440,6 @@ public class TemperatureTriggerHandler extends BaseTriggerModuleHandler
|
|||
}
|
||||
```
|
||||
|
||||
|
||||
### Condition Handler
|
||||
|
||||
Condition Handler serves to help the Automation Engine to decide if it continues with the execution of the rule or to terminate it.
|
||||
|
@ -470,6 +471,7 @@ public class PresenceConditionHandler extends BaseModuleHandler<Condition> imple
|
|||
|
||||
}
|
||||
```
|
||||
|
||||
### Action Handler
|
||||
|
||||
Action Handler is used to help the Automation Engine to execute the specific Actions.
|
||||
|
@ -490,17 +492,17 @@ The automation engine reads rule json files from the `{openhab-dir}/automation/*
|
|||
The rule that implements our application is declaratively described in the json format like this:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
[
|
||||
{
|
||||
"uid":"JsonDemoRule",
|
||||
"name":"DemoRule",
|
||||
"triggers":[
|
||||
{
|
||||
{
|
||||
"id":"RuleTrigger",
|
||||
"label":"Item State Change Trigger",
|
||||
"description":"This triggers a rule if an items state changed",
|
||||
"type":"ItemStateChangeTrigger",
|
||||
"configuration":{
|
||||
"configuration":{
|
||||
"itemName":"DemoSwitch"
|
||||
}
|
||||
}
|
||||
|
@ -508,12 +510,12 @@ The rule that implements our application is declaratively described in the json
|
|||
"conditions":[
|
||||
],
|
||||
"actions":[
|
||||
{
|
||||
{
|
||||
"id":"RuleAction",
|
||||
"label":"Post command to an item",
|
||||
"description":"Posts commands on items",
|
||||
"type":"ItemPostCommandAction",
|
||||
"configuration":{
|
||||
"configuration":{
|
||||
"itemName":"DemoDimmer",
|
||||
"command":"ON"
|
||||
}
|
||||
|
|
|
@ -9,15 +9,13 @@ title: Configuration Admin
|
|||
|
||||
As defined in the [OSGi Compendium Release 7][OSGi-cmpn] *configuration is the process of defining the configuration data of bundles and assuring that those bundles receive that data when they are active in the OSGi Service Platform.*
|
||||
|
||||
### Configuration Admin Service
|
||||
|
||||
In OSGi, configurations are stored in a central database that is being managed by a special service - the *Configuration Admin Service*(`org.osgi.service.cm.ConfigurationAdmin`).
|
||||
This service monitors the service registry and **provides a configuration to the services** that are registered with a *service.pid* property.
|
||||
Configuration changes are first made persistent, and then are passed to the target service.
|
||||
It is important to understand that **the target bundle receives updates from the Configuration Admin service**.
|
||||
Implementations should be aware that the update reception could be delayed if the Configuration Admin service is missing.
|
||||
|
||||
### Configuration properties
|
||||
## Configuration properties
|
||||
|
||||
Each configuration is uniquely identified by a PID (Persistent IDentifier) and stores properties.
|
||||
The properties can be edited, or new properties could be added during runtime by other bundle that uses the Configuration Admin service.
|
||||
|
|
|
@ -16,7 +16,7 @@ The openHAB bundles are deployed on an Equinox runtime.
|
|||
Knowledge about how to start the runtime and execute basic commands will help you to speedup the development process.
|
||||
|
||||
{::options toc_levels="2,3"/}
|
||||
* TOC
|
||||
- TOC
|
||||
{:toc}
|
||||
|
||||
## Start Equinox Runtime from Eclipse
|
||||
|
@ -46,8 +46,8 @@ Find it in your maven cache directory (linux `~/.m2/repository/org/eclipse/platf
|
|||
and windows `C:\Users\your.name\.m2\..`).
|
||||
|
||||
1. Create `configuration` folder in that directory.
|
||||
2. Inside the `configuration` folder create a file `config.ini`.
|
||||
3. Save the following content in the `config.ini` file:
|
||||
1. Inside the `configuration` folder create a file `config.ini`.
|
||||
1. Save the following content in the `config.ini` file:
|
||||
|
||||
```ini
|
||||
osgi.bundles=\
|
||||
|
@ -67,7 +67,7 @@ and windows `C:\Users\your.name\.m2\..`).
|
|||
eclipse.consoleLog=true
|
||||
```
|
||||
|
||||
6. Use the following command line to run Equinox:
|
||||
1. Use the following command line to run Equinox:
|
||||
|
||||
```shell
|
||||
java -jar org.eclipse.osgi-3.x.x.jar -console -configuration configuration
|
||||
|
|
|
@ -64,8 +64,8 @@ public class LogEventHandler implements EventHandler {
|
|||
}
|
||||
```
|
||||
|
||||
* You can register a handler for multiple topics by separating them by comma: `event.topics=some/topic,other/topic`
|
||||
* You can register for all events with `*`.
|
||||
- You can register a handler for multiple topics by separating them by comma: `event.topics=some/topic,other/topic`
|
||||
- You can register for all events with `*`.
|
||||
|
||||
## Send Events
|
||||
|
||||
|
@ -78,9 +78,9 @@ The service contains two methods for sending events:
|
|||
|
||||
## Further Reading
|
||||
|
||||
- [OSGi Compendium Release 7][OSGi-cmpn]
|
||||
- <https://enroute.osgi.org/services/org.osgi.service.event.html>
|
||||
- <http://blog.vogella.com/2017/05/16/osgi-event-admin-publish-subscribe/>
|
||||
- [OSGi Compendium Release 7][OSGi-cmpn]
|
||||
- <https://enroute.osgi.org/services/org.osgi.service.event.html>
|
||||
- <http://blog.vogella.com/2017/05/16/osgi-event-admin-publish-subscribe/>
|
||||
|
||||
[fig1]:images/event-admin.png
|
||||
|
||||
|
|
|
@ -6,13 +6,14 @@ title: OSGi
|
|||
{% include base.html %}
|
||||
|
||||
# OSGi Overview
|
||||
|
||||
{:.no_toc}
|
||||
|
||||
openHAB is being based on [OSGi][OSGi] and understanding of OSGi modular architecture is very important.
|
||||
This page is aimed to help developers, that are going to use OSGi for the first time and contains a basic overview of the OSGi technology.
|
||||
|
||||
{::options toc_levels="2,3"/}
|
||||
* TOC
|
||||
- TOC
|
||||
{:toc}
|
||||
|
||||
## Concepts
|
||||
|
@ -31,11 +32,11 @@ Key features of OSGi are:
|
|||
|
||||
The OSGi framework consist of several layers build on top of each other (See Fig. 1):
|
||||
|
||||
- **Module Layer** - it is responsible for managing dependencies between bundles and for class loading ([See Bundles Section](#bundles));
|
||||
- **Life Cycle Layer** - controls the lifecycle of the bundles ([See Lifecycle Section](#lifecycle));
|
||||
- **Service Layer** - defines a dynamic model (publish/find/bind) of communication between different modules ([See Services Section](#services));
|
||||
- **Actual Services** (Bundles on Fig.1) - this is the application layer, using all other layers;
|
||||
- **Security Layer** - optional layer, based on the Java 2 security architecture, that manages permissions for different modules.
|
||||
- **Module Layer** - it is responsible for managing dependencies between bundles and for class loading ([See Bundles Section](#bundles));
|
||||
- **Life Cycle Layer** - controls the lifecycle of the bundles ([See Lifecycle Section](#lifecycle));
|
||||
- **Service Layer** - defines a dynamic model (publish/find/bind) of communication between different modules ([See Services Section](#services));
|
||||
- **Actual Services** (Bundles on Fig.1) - this is the application layer, using all other layers;
|
||||
- **Security Layer** - optional layer, based on the Java 2 security architecture, that manages permissions for different modules.
|
||||
|
||||
![OSGi Layers][fig1]
|
||||
Fig.1 OSGi Layering (Source:<https://www.osgi.org/wp-content/uploads/layering-osgi.png>)
|
||||
|
@ -168,12 +169,12 @@ We will list the most popular OSGi containers with a short description of their
|
|||
|
||||
## Further Reading
|
||||
|
||||
- [OSGi Core Release 7][OSGi-core]
|
||||
- [OSGi API](https://osgi.org/javadoc/osgi.core/7.0.0/)
|
||||
- [OSGi Vogella guide](http://www.vogella.com/tutorials/OSGi/article.html)
|
||||
- [Lifecycle of a bundle](https://developer.atlassian.com/docs/atlassian-platform-common-components/plugin-framework/behind-the-scenes-in-the-plugin-framework/lifecycle-of-a-bundle)
|
||||
- [OSGi enRoute](https://enroute.osgi.org/)
|
||||
- <https://www.osgi.org/developer/where-to-start/>
|
||||
- [OSGi Core Release 7][OSGi-core]
|
||||
- [OSGi API](https://osgi.org/javadoc/osgi.core/7.0.0/)
|
||||
- [OSGi Vogella guide](http://www.vogella.com/tutorials/OSGi/article.html)
|
||||
- [Lifecycle of a bundle](https://developer.atlassian.com/docs/atlassian-platform-common-components/plugin-framework/behind-the-scenes-in-the-plugin-framework/lifecycle-of-a-bundle)
|
||||
- [OSGi enRoute](https://enroute.osgi.org/)
|
||||
- <https://www.osgi.org/developer/where-to-start/>
|
||||
|
||||
[OSGi]: https://www.osgi.org/
|
||||
[OSGi-core]: https://osgi.org/download/r7/osgi.core-7.0.0.pdf
|
||||
|
|
|
@ -6,6 +6,7 @@ title: OSGi Declarative Services
|
|||
{% include base.html %}
|
||||
|
||||
# Declarative Services
|
||||
|
||||
{:.no_toc}
|
||||
|
||||
In the [OSGi Overview article](osgi.html) we have mentioned that a bundle can register, unregister, get and unget services from a central point - the Service Registry.
|
||||
|
@ -13,14 +14,16 @@ In the [OSGi Overview article](osgi.html) we have mentioned that a bundle can re
|
|||
In order to simplify the usage of services the [OSGi Alliance](https://www.osgi.org/about-us/) has developed a model of managing services dynamically called *Declarative Services*.
|
||||
|
||||
{::options toc_levels="2"/}
|
||||
* TOC
|
||||
|
||||
- TOC
|
||||
|
||||
{:toc}
|
||||
|
||||
## Model & Terms
|
||||
|
||||
In order to understand this model, we will have to first explain a few terms, used below:
|
||||
|
||||
- **Declarative Services Container** (we will use the shorthand **DS**) - a module that is managing the [lifecycle](#vii-component-lifecycle) of a *service component* dynamically.
|
||||
- **Declarative Services Container** (we will use the shorthand **DS**) - a module that is managing the [lifecycle](#vii-component-lifecycle) of a *service component- dynamically.
|
||||
It activates and deactivates different components, basing its decisions on the information contained in the *component description*;
|
||||
- **Service Component** (or also **component**) - an object whose lifecycle is managed,
|
||||
usually by a component framework such as Declarative Services (DS).
|
||||
|
@ -41,7 +44,7 @@ This ensures that service components are managed dynamically.
|
|||
|
||||
## Components
|
||||
|
||||
It is important to understand the difference between a *component* and a *service*.
|
||||
It is important to understand the difference between a *component** and a *service*.
|
||||
A component is a normal Java class, that can reference services and provide services.
|
||||
What makes a component specific is that it is declared in a XML file and is managed completely by DS.
|
||||
That means that DS instantiates the component, calls method on this component and manages the lifecycle of a component.
|
||||
|
@ -112,16 +115,16 @@ public class MyService {
|
|||
Let's take a look at some configuration parameters, that we can apply:
|
||||
|
||||
- **immediate**:
|
||||
- *true* - the component is activated as soon as all dependencies are satisfied. Adding this option will ensure that the component will be activated right after the bundle is activated and the component is satisfied;
|
||||
- *false* - the component has lazy activation. The activation of the component is delayed(lazy activation) until the service is requested. This is the default value;
|
||||
- *true- - the component is activated as soon as all dependencies are satisfied. Adding this option will ensure that the component will be activated right after the bundle is activated and the component is satisfied;
|
||||
- *false- - the component has lazy activation. The activation of the component is delayed(lazy activation) until the service is requested. This is the default value;
|
||||
- **cardinality**:
|
||||
- *1..1* - single service reference, that is mandatory. If your referenced service gets inactive, DS deactivates your service component as well (default value);
|
||||
- *0..1* - single service reference(not mandatory). You have to be aware that you might not have your reference resolved, your component can live with the absence;
|
||||
- *0..n* - multiple service references (not mandatory). The referenced service can be implemented multiple times, so they are added to a list in your component implementation;
|
||||
- *1..n* = like the above, but mandatory;
|
||||
- *1..1- - single service reference, that is mandatory. If your referenced service gets inactive, DS deactivates your service component as well (default value);
|
||||
- *0..1- - single service reference(not mandatory). You have to be aware that you might not have your reference resolved, your component can live with the absence;
|
||||
- *0..n- - multiple service references (not mandatory). The referenced service can be implemented multiple times, so they are added to a list in your component implementation;
|
||||
- *1..n- = like the above, but mandatory;
|
||||
- **policy**:
|
||||
- *static* - the default policy. Component configuration are deactivated every time, when a reference with static policy becomes unavailable. This causes the activating and deactivating of the component. It can be very expensive, when we have multiple bound services, or when a service is often unregistered and re-registered;
|
||||
- *dynamic* - with this policy the component is not deactivated, when a referenced service is changed. It is slightly more complex, as the component implementation has to properly handle changes in the set of bound services.
|
||||
- *static- - the default policy. Component configuration are deactivated every time, when a reference with static policy becomes unavailable. This causes the activating and deactivating of the component. It can be very expensive, when we have multiple bound services, or when a service is often unregistered and re-registered;
|
||||
- *dynamic- - with this policy the component is not deactivated, when a referenced service is changed. It is slightly more complex, as the component implementation has to properly handle changes in the set of bound services.
|
||||
|
||||
### Method Injection
|
||||
|
||||
|
@ -208,7 +211,7 @@ You can find more information in the [OSGi Compendium Release 7, Chapter 112.2:
|
|||
A component goes through several states in his lifecycle:
|
||||
|
||||
- **UNSATISFIED** - initial state of the Service Component, after the bundle is started;
|
||||
- **REGISTERED** - temporary state. Only *delayed* components go through this state;
|
||||
- **REGISTERED** - temporary state. Only *delayed- components go through this state;
|
||||
- **ACTIVE** - the component is active and component instance is created.
|
||||
|
||||
<img src="images/immediatecomponent.png" width="320" height="200" />
|
||||
|
@ -229,8 +232,8 @@ The next step is to satisfy the component configuration.
|
|||
|
||||
The component **configuration is satisfied** when:
|
||||
|
||||
- component is **enabled**;
|
||||
- all the **component references are satisfied**.
|
||||
- component is **enabled**;
|
||||
- all the **component references are satisfied**.
|
||||
A reference is satisfied when the reference specifies optional cardinality or there is at least one target service for the reference.
|
||||
If the component has lazy initialization (the component is *delayed*), it is moved to the REGISTERED state and it is waiting to be activated, when the service is requested (see Fig.2).
|
||||
Otherwise (the component is *immediate*) as soon as its dependencies are satisfied, the component is activated (see Fig.1).
|
||||
|
@ -245,15 +248,15 @@ Activation consists of following steps:
|
|||
- The method that is annotated with `@Activate` is called, if present
|
||||
|
||||
After the activation, the component is in ACTIVE state.
|
||||
From this state the component can go back to the *REGISTERED* state (or to the *UNSATISFIED* state), if the component configuration becomes unsatisfied.
|
||||
From this state the component can go back to the *REGISTERED- state (or to the*UNSATISFIED- state), if the component configuration becomes unsatisfied.
|
||||
|
||||
### Deactivation
|
||||
|
||||
Deactivation consists of the following actions:
|
||||
|
||||
- The method that is annotated with `@Deactivate` is called, if present
|
||||
- All `@Reference`d services are unbound
|
||||
- Release all references to the component instance.
|
||||
- The method that is annotated with `@Deactivate` is called, if present
|
||||
- All `@Reference`d services are unbound
|
||||
- Release all references to the component instance.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
|
|
|
@ -7,4 +7,4 @@ title: Persistence Service
|
|||
|
||||
# Developing a Persistence Service
|
||||
|
||||
TODO
|
||||
TODO
|
||||
|
|
|
@ -42,9 +42,9 @@ assertThat(pt.toString(), is(equalTo("0.0001")));
|
|||
|
||||
### Mockito
|
||||
|
||||
In order to keep tests as focused as possible we use the mocking framework [https://github.com/mockito/mockito Mockito].
|
||||
In order to keep tests as focused as possible we use the mocking framework [<https://github.com/mockito/mockito> Mockito].
|
||||
Mockito lets us verify interactions between supporting classes and the unit under test and additionally supports stubbing of method calls for these classes.
|
||||
Please read the very short but expressive introduction on the [https://site.mockito.org/ Mockito homepage] in addition to this small example:
|
||||
Please read the very short but expressive introduction on the [<https://site.mockito.org/> Mockito homepage] in addition to this small example:
|
||||
|
||||
```java
|
||||
public class MyBindingHandlerTest {
|
||||
|
@ -199,9 +199,9 @@ At the end the mock is unregistered again.
|
|||
|
||||
## Common errors
|
||||
|
||||
### Failed to execute goal org.eclipse.tycho:tycho-surefire-plugin:XXX:test (default-test) on project XXX: No tests found.
|
||||
### Failed to execute goal org.eclipse.tycho:tycho-surefire-plugin:XXX:test (default-test) on project XXX: No tests found
|
||||
|
||||
Maven might report this error when building your project, it means that the maven surefire plugin cannot find any tests to execute, please check the following details:
|
||||
|
||||
* Did you add any test classes with a class-name which ends with `Test` (singular)
|
||||
* Did you annotate any methods with `@Test`
|
||||
- Did you add any test classes with a class-name which ends with `Test` (singular)
|
||||
- Did you annotate any methods with `@Test`
|
||||
|
|
|
@ -42,7 +42,6 @@ Next you implement the `transform` method. You are given a user configuration an
|
|||
In our case we do not use the `config` parameter.
|
||||
Other services like the regex or map transformation are using this parameter for the regex ("`.*=(\\d*.\\d*).*`") or the map (`mapfile.map`) for example.
|
||||
|
||||
|
||||
Our implementation is as simple as this:
|
||||
|
||||
```java
|
||||
|
@ -61,28 +60,28 @@ just like transformations.
|
|||
|
||||
But in contrast to transformations, if one Channel is linked to several Items it also will have several profile instances.
|
||||
Each instance handling the communication to exactly one of these Items.
|
||||
The same applies for the situation where one Item is linked to multiple Channels.
|
||||
The same applies for the situation where one Item is linked to multiple Channels.
|
||||
|
||||
Profiles are created by ProfileFactories and are retained for the lifetime of their link.
|
||||
Profiles are created by ProfileFactories and are retained for the lifetime of their link.
|
||||
This means that they are, in contrast to transformations, allowed to retain a transient state,
|
||||
like e.g. the timestamp of the the last event or the last state.
|
||||
like e.g. the timestamp of the the last event or the last state.
|
||||
With this, it is possible to take into account the temporal dimension when calculating the appropriate action in any situation.
|
||||
|
||||
There exist two different kinds of profiles: state and trigger profiles.
|
||||
|
||||
## State Profiles
|
||||
|
||||
State profiles are responsible for communication between Items and their corresponding state Channels (`ChannelKind.STATE`).
|
||||
State profiles are responsible for communication between Items and their corresponding state Channels (`ChannelKind.STATE`).
|
||||
Their purpose is to forward state updates and commands to and from the Thing handlers.
|
||||
|
||||
## Trigger Profiles
|
||||
|
||||
Trigger Channels (`ChannelKind.TRIGGER`) by themselves do not maintain a state (as by their nature they only fire events).
|
||||
With the help of trigger profiles they can be linked to Items anyway.
|
||||
Hence the main purpose of a trigger profile is to calculate a state based on the fired events.
|
||||
This state then is forwarded to the linked Item by sending `ItemStateEvents`.
|
||||
Trigger Channels (`ChannelKind.TRIGGER`) by themselves do not maintain a state (as by their nature they only fire events).
|
||||
With the help of trigger profiles they can be linked to Items anyway.
|
||||
Hence the main purpose of a trigger profile is to calculate a state based on the fired events.
|
||||
This state then is forwarded to the linked Item by sending `ItemStateEvents`.
|
||||
|
||||
Trigger profiles are powerful means to implement some immediate, straight-forward logic without the need to write any rules.
|
||||
Trigger profiles are powerful means to implement some immediate, straight-forward logic without the need to write any rules.
|
||||
|
||||
Apart from that, they do not pass any commands or state updates to and from the Thing handler as by their nature trigger Channels are not capable of handling these.
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ This section introduces the event API and illustrates how to receive such events
|
|||
Furthermore, the sending of events and the implementation of new event types will be described.
|
||||
|
||||
{::options toc_levels="2,3"/}
|
||||
* TOC
|
||||
- TOC
|
||||
{:toc}
|
||||
|
||||
## API Introduction
|
||||
|
|
|
@ -11,7 +11,7 @@ title: Internationalization
|
|||
In this chapter the openHAB support for internationalization is described.
|
||||
|
||||
{::options toc_levels="2,3"/}
|
||||
* TOC
|
||||
- TOC
|
||||
{:toc}
|
||||
|
||||
## Folder and File Structure
|
||||
|
@ -20,7 +20,7 @@ All texts can be internationalized by using Java i18n properties files.
|
|||
For each language a specific file with a postfix notation is used.
|
||||
The postfix consists of a language code and an optional region code (country code).
|
||||
|
||||
```
|
||||
```text
|
||||
Format: any_<language-code>_<country-code>.properties
|
||||
Example: any_de_DE.properties
|
||||
```
|
||||
|
@ -30,7 +30,7 @@ The region code (country code) consists of two uppercase letters that are confor
|
|||
|
||||
The search order for those files is the following:
|
||||
|
||||
```
|
||||
```text
|
||||
any_<language-code>_<country-code>.properties
|
||||
any_<language-code>.properties
|
||||
any.properties
|
||||
|
@ -40,13 +40,13 @@ You can find detailed information about Java internationalization support and a
|
|||
|
||||
The properties files have to be placed in the following directory of the bundle:
|
||||
|
||||
```
|
||||
```text
|
||||
OH-INF/i18n
|
||||
```
|
||||
|
||||
Example files:
|
||||
|
||||
```
|
||||
```text
|
||||
|- OH-INF
|
||||
|---- i18n
|
||||
|------- yahooweather.properties
|
||||
|
@ -75,7 +75,7 @@ XML file (`binding.xml`):
|
|||
<binding:binding id="yahooweather">
|
||||
<name>YahooWeather Binding</name>
|
||||
<description>The Yahoo Weather Binding requests the Yahoo Weather Service
|
||||
to show the current temperature, humidity and pressure.</description>
|
||||
to show the current temperature, humidity and pressure.</description>
|
||||
<author>Kai Kreuzer</author>
|
||||
</binding:binding>
|
||||
```
|
||||
|
|
|
@ -45,7 +45,7 @@ The framework provides some caching solutions for common scenarios.
|
|||
A common usage case is in a `ThingHandler` to encapsulate one value of an internal state and attach an expire time on that value.
|
||||
A cache action will be called to refresh the value if it is expired.
|
||||
This is what `ExpiringCache` implements.
|
||||
If `handleCommand(ChannelUID channelUID, Command command)` is called with the "RefreshType" command, you just return `cache.getValue()`.
|
||||
If `handleCommand(ChannelUID channelUID, Command command)` is called with the "RefreshType" command, you just return `cache.getValue()`.
|
||||
|
||||
It is a good practice to return as fast as possible from the `handleCommand(ChannelUID channelUID, Command command)` method to not block callers especially UIs.
|
||||
Use this type of cache only, if your refresh action is a quick to compute, blocking operation.
|
||||
|
@ -58,7 +58,6 @@ If the state is too old, we need to fetch it first and this may involve network
|
|||
|
||||
A common usage case of the `ExpiringCacheAsync` cache type is in a `ThingHandler` to encapsulate one value of an internal state and attach an expire time on that value.
|
||||
|
||||
|
||||
A **handleCommand** implementation with the interesting *RefreshType* could look like this:
|
||||
|
||||
```java
|
||||
|
@ -91,7 +90,7 @@ and mark the Future as *complete*.
|
|||
```java
|
||||
class FetchValueFromDevice implements Supplier<CompletableFuture<double>>, DeviceStateUpdateListener {
|
||||
CompletableFuture<double> c;
|
||||
|
||||
|
||||
@Override
|
||||
CompletableFuture<double> get() {
|
||||
if (c != null) {
|
||||
|
@ -100,7 +99,7 @@ class FetchValueFromDevice implements Supplier<CompletableFuture<double>>, Devic
|
|||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
// Here you process the callback from your device refresh method
|
||||
@Override
|
||||
void asyncCallbackFromDeviceStateRefresh(double newValue) {
|
||||
|
@ -112,5 +111,6 @@ class FetchValueFromDevice implements Supplier<CompletableFuture<double>>, Devic
|
|||
}
|
||||
}
|
||||
```
|
||||
|
||||
If you deal with a newer implementation with a CompletableFuture support, it is even easier.
|
||||
You would just return your CompletableFuture.
|
||||
|
|
Loading…
Reference in New Issue