Skip to content
This repository has been archived by the owner on May 7, 2020. It is now read-only.

Commit

Permalink
allow referencing a channel type in the DSL (#2343)
Browse files Browse the repository at this point in the history
in the Thing DSL it is possible to define channels manually.
However, it was not possible so far to reference a binding's
channel type which is defined in the XMLs.

Signed-off-by: Simon Kaufmann <simon.kfm@googlemail.com>
  • Loading branch information
Simon Kaufmann authored and kaikreuzer committed Oct 28, 2016
1 parent d38740c commit e61e10e
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import org.eclipse.smarthome.core.thing.Bridge
import org.eclipse.smarthome.core.thing.Channel
import org.eclipse.smarthome.core.thing.Thing
import org.eclipse.smarthome.core.thing.ThingRegistry
import org.eclipse.smarthome.core.thing.type.ChannelKind
import org.eclipse.smarthome.core.thing.type.ChannelTypeUID
import org.eclipse.smarthome.model.core.ModelRepository
import org.eclipse.smarthome.test.OSGiTest
import org.junit.After
Expand Down Expand Up @@ -279,4 +281,45 @@ class GenericThingProviderTest extends OSGiTest {
assertThat bridge.things.contains(thing), is(true)
}

@Test
void 'assert that channel definitions can be referenced'() {
def things = thingRegistry.getAll()
assertThat things.size(), is(0)

String model =
'''
Bridge hue:bridge:bridge1 [] {
LCT001 bulb_default []
LCT001 bulb_custom [] {
Channels:
Type color : manual []
}
LCT001 bulb_broken [] {
Channels:
Type broken : manual []
}
}
'''

modelRepository.addOrRefreshModel(TESTMODEL_NAME, new ByteArrayInputStream(model.bytes))
def List<Thing> actualThings = thingRegistry.getAll()

assertThat actualThings.size(), is(4)

Thing thingDefault = actualThings.find { it.getUID().getId().equals("bulb_default") }
assertThat thingDefault.getChannels().size(), is(2)

Thing thingCustom = actualThings.find { it.getUID().getId().equals("bulb_custom") }
assertThat thingCustom.getChannels().size(), is(3)
assertThat thingCustom.getChannel("manual").getChannelTypeUID(), is(equalTo(new ChannelTypeUID("hue", "color")))

Thing thingBroken = actualThings.find { it.getUID().getId().equals("bulb_broken") }
assertThat thingBroken.getChannels().size(), is(3)
assertThat thingBroken.getChannel("manual").getChannelTypeUID(), is(equalTo(new ChannelTypeUID("hue", "broken")))
assertThat thingBroken.getChannel("manual").getKind(), is(ChannelKind.STATE)
assertThat thingBroken.getChannel("manual").getAcceptedItemType(), is(nullValue())

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ ModelThing:
;

ModelChannel:
(channelKind= ('State' | 'Trigger'))? type=ModelItemType ':' id=UID_SEGMENT
(((channelKind= ('State' | 'Trigger'))? type=ModelItemType) | 'Type' channelType=UID_SEGMENT) ':' id=UID_SEGMENT
('['
properties+=ModelProperty (',' properties+=ModelProperty)*
']')?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import org.eclipse.smarthome.core.thing.type.TypeResolver
import java.util.Locale
import org.eclipse.smarthome.core.i18n.LocaleProvider
import org.eclipse.smarthome.core.thing.type.ChannelKind
import org.eclipse.smarthome.core.thing.type.ChannelTypeUID

/**
* {@link ThingProvider} implementation which computes *.things files.
Expand Down Expand Up @@ -275,11 +276,30 @@ class GenericThingProvider extends AbstractProvider<Thing> implements ThingProvi
val List<Channel> channels = newArrayList
modelChannels.forEach [
if (addedChannelIds.add(id)) {
val kind = if (it.channelKind == null) "State" else it.channelKind
val parsedKind = ChannelKind.parse(kind)
val channel = ChannelBuilder.create(new ChannelUID(thingTypeUID, thingUID, id), type)
var ChannelKind parsedKind = ChannelKind.STATE

var ChannelTypeUID channelTypeUID
var String itemType
if (it.channelType != null) {
channelTypeUID = new ChannelTypeUID(thingUID.bindingId, it.channelType)
val resolvedChannelType = TypeResolver.resolve(channelTypeUID)
if (resolvedChannelType != null) {
itemType = resolvedChannelType.itemType
parsedKind = resolvedChannelType.kind
} else {
logger.error("Channel type {} could not be resolved.", channelTypeUID.asString)
}
} else {
itemType = it.type

val kind = if (it.channelKind == null) "State" else it.channelKind
parsedKind = ChannelKind.parse(kind)
}

var channel = ChannelBuilder.create(new ChannelUID(thingUID, id), itemType)
.withKind(parsedKind)
.withConfiguration(createConfiguration)
.withType(channelTypeUID)
channels += channel.build()
}
]
Expand Down
31 changes: 31 additions & 0 deletions docs/documentation/features/dsl.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,34 @@ Thing yahooweather:weather:losangeles [ location=2442047, unit="us", refresh=120
```

Trigger channels are defined with the keyword `Trigger` and only support the type String.

### Referencing existing channel types

Many bindings provide standalone channel type definitions like this:

```
<thing:thing-descriptions bindingId="yahooweather" [...]>
<channel-type id="temperature">
<item-type>Number</item-type>
<label>Temperature</label>
<description>Current temperature in degrees celsius</description>
<category>Temperature</category>
<state readOnly="true" pattern="%.1f °C">
</state>
</channel-type>
[...]
</thing:thing-descriptions>
```

They can be referenced within a thing's channel definition, so that they need to be defined only once and can be reused for many channels. You may do so in the DSL as well:

```
Thing yahooweather:weather:losangeles [ location=2442047, unit="us", refresh=120 ] {
Channels:
Type temperature : my_yesterday_temperature
}
```

The `Type` keyword indicates a reference to an existing channel definition. The channel kind and accepted item types of course are takes from the channel definition, therefore they don't need to be specified here again.


0 comments on commit e61e10e

Please sign in to comment.