Added Magic Button triggering some events every 5 seconds (#2569)

Signed-off-by: Christoph Weitkamp <github@christophweitkamp.de>
pull/2572/head
Christoph Weitkamp 2021-11-18 16:03:06 +01:00 committed by GitHub
parent f9d201c35b
commit fea3615109
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 271 additions and 64 deletions

View File

@ -30,6 +30,7 @@ public class MagicBindingConstants {
// generic thing types
public static final ThingTypeUID THING_TYPE_EXTENSIBLE_THING = new ThingTypeUID(BINDING_ID, "extensible-thing");
public static final ThingTypeUID THING_TYPE_BUTTON = new ThingTypeUID(BINDING_ID, "button");
public static final ThingTypeUID THING_TYPE_ON_OFF_LIGHT = new ThingTypeUID(BINDING_ID, "onoff-light");
public static final ThingTypeUID THING_TYPE_DIMMABLE_LIGHT = new ThingTypeUID(BINDING_ID, "dimmable-light");
public static final ThingTypeUID THING_TYPE_COLOR_LIGHT = new ThingTypeUID(BINDING_ID, "color-light");
@ -54,6 +55,8 @@ public class MagicBindingConstants {
public static final ThingTypeUID THING_TYPE_BRIDGED_THING = new ThingTypeUID(BINDING_ID, "bridgedThing");
// List all channels
public static final String CHANNEL_RAWBUTTON = "rawbutton";
public static final String CHANNEL_BUTTON = "button";
public static final String CHANNEL_SWITCH = "switch";
public static final String CHANNEL_BRIGHTNESS = "brightness";
public static final String CHANNEL_COLOR = "color";
@ -61,6 +64,7 @@ public class MagicBindingConstants {
public static final String CHANNEL_LOCATION = "location";
public static final String CHANNEL_TEMPERATURE = "temperature";
public static final String CHANNEL_SET_TEMPERATURE = "set-temperature";
public static final String CHANNEL_BATTERY_LEVEL = "battery-level";
public static final String CHANNEL_SYSTEM_COMMAND = "systemcommand";
public static final String CHANNEL_SIGNAL_STRENGTH = "signal-strength";

View File

@ -0,0 +1,77 @@
/**
* Copyright (c) 2010-2021 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.core.magic.binding.handler;
import static org.openhab.core.magic.binding.MagicBindingConstants.CHANNEL_RAWBUTTON;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.CommonTriggerEvents;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.types.Command;
/**
* The {@link MagicButtonHandler} is capable of triggering different events. Triggers a PRESSED event every 5 seconds on
* the rawbutton trigger channel.
*
* @author Christoph Weitkamp - Initial contribution
*/
@NonNullByDefault
public class MagicButtonHandler extends BaseThingHandler {
private @Nullable ScheduledFuture<?> scheduledJob;
public MagicButtonHandler(Thing thing) {
super(thing);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
// no-op
}
@Override
public void initialize() {
startScheduledJob();
updateStatus(ThingStatus.ONLINE);
}
@Override
public void dispose() {
stopScheduledJob();
}
private void startScheduledJob() {
ScheduledFuture<?> localScheduledJob = scheduledJob;
if (localScheduledJob == null || localScheduledJob.isCancelled()) {
scheduledJob = scheduler.scheduleWithFixedDelay(() -> {
triggerChannel(CHANNEL_RAWBUTTON, CommonTriggerEvents.PRESSED);
}, 5, 5, TimeUnit.SECONDS);
}
}
private void stopScheduledJob() {
ScheduledFuture<?> localScheduledJob = scheduledJob;
if (localScheduledJob != null && !localScheduledJob.isCancelled()) {
localScheduledJob.cancel(true);
scheduledJob = null;
}
}
}

View File

@ -20,15 +20,15 @@ import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.types.Command;
/**
* The {@link MagicRolllershutterHandler} is responsible for handling commands, which are
* The {@link MagicRollershutterHandler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Henning Treu - Initial contribution
*/
@NonNullByDefault
public class MagicRolllershutterHandler extends BaseThingHandler {
public class MagicRollershutterHandler extends BaseThingHandler {
public MagicRolllershutterHandler(Thing thing) {
public MagicRollershutterHandler(Thing thing) {
super(thing);
}

View File

@ -19,6 +19,7 @@ import java.util.concurrent.TimeUnit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
@ -51,6 +52,10 @@ public class MagicThermostatThingHandler extends BaseThingHandler {
@Override
public void initialize() {
updateState(CHANNEL_TEMPERATURE, new QuantityType<>(21, SIUnits.CELSIUS));
updateState(CHANNEL_SET_TEMPERATURE, new QuantityType<>(21, SIUnits.CELSIUS));
updateState(CHANNEL_BATTERY_LEVEL, new DecimalType(23));
updateStatus(ThingStatus.ONLINE);
}
}

View File

@ -21,6 +21,7 @@ import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.magic.binding.handler.MagicActionModuleThingHandler;
import org.openhab.core.magic.binding.handler.MagicBridgeHandler;
import org.openhab.core.magic.binding.handler.MagicBridgedThingHandler;
import org.openhab.core.magic.binding.handler.MagicButtonHandler;
import org.openhab.core.magic.binding.handler.MagicChattyThingHandler;
import org.openhab.core.magic.binding.handler.MagicColorLightHandler;
import org.openhab.core.magic.binding.handler.MagicConfigurableThingHandler;
@ -35,7 +36,7 @@ import org.openhab.core.magic.binding.handler.MagicLocationThingHandler;
import org.openhab.core.magic.binding.handler.MagicOnOffLightHandler;
import org.openhab.core.magic.binding.handler.MagicOnlineOfflineHandler;
import org.openhab.core.magic.binding.handler.MagicPlayerHandler;
import org.openhab.core.magic.binding.handler.MagicRolllershutterHandler;
import org.openhab.core.magic.binding.handler.MagicRollershutterHandler;
import org.openhab.core.magic.binding.handler.MagicThermostatThingHandler;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
@ -57,11 +58,12 @@ import org.osgi.service.component.annotations.Reference;
public class MagicHandlerFactory extends BaseThingHandlerFactory {
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_EXTENSIBLE_THING,
THING_TYPE_ON_OFF_LIGHT, THING_TYPE_DIMMABLE_LIGHT, THING_TYPE_COLOR_LIGHT, THING_TYPE_CONTACT_SENSOR,
THING_TYPE_CONFIG_THING, THING_TYPE_DELAYED_THING, THING_TYPE_LOCATION, THING_TYPE_THERMOSTAT,
THING_TYPE_FIRMWARE_UPDATE, THING_TYPE_BRIDGE_1, THING_TYPE_BRIDGE_2, THING_TYPE_BRIDGED_THING,
THING_TYPE_CHATTY_THING, THING_TYPE_ROLLERSHUTTER, THING_TYPE_PLAYER, THING_TYPE_IMAGE,
THING_TYPE_ACTION_MODULE, THING_TYPE_DYNAMIC_STATE_DESCRIPTION, THING_TYPE_ONLINE_OFFLINE);
THING_TYPE_BUTTON, THING_TYPE_ON_OFF_LIGHT, THING_TYPE_DIMMABLE_LIGHT, THING_TYPE_COLOR_LIGHT,
THING_TYPE_CONTACT_SENSOR, THING_TYPE_CONFIG_THING, THING_TYPE_DELAYED_THING, THING_TYPE_LOCATION,
THING_TYPE_THERMOSTAT, THING_TYPE_FIRMWARE_UPDATE, THING_TYPE_BRIDGE_1, THING_TYPE_BRIDGE_2,
THING_TYPE_BRIDGED_THING, THING_TYPE_CHATTY_THING, THING_TYPE_ROLLERSHUTTER, THING_TYPE_PLAYER,
THING_TYPE_IMAGE, THING_TYPE_ACTION_MODULE, THING_TYPE_DYNAMIC_STATE_DESCRIPTION,
THING_TYPE_ONLINE_OFFLINE);
private final MagicDynamicCommandDescriptionProvider commandDescriptionProvider;
private final MagicDynamicStateDescriptionProvider stateDescriptionProvider;
@ -84,60 +86,44 @@ public class MagicHandlerFactory extends BaseThingHandlerFactory {
if (THING_TYPE_EXTENSIBLE_THING.equals(thingTypeUID)) {
return new MagicExtensibleThingHandler(thing);
}
if (THING_TYPE_ON_OFF_LIGHT.equals(thingTypeUID)) {
} else if (THING_TYPE_BUTTON.equals(thingTypeUID)) {
return new MagicButtonHandler(thing);
} else if (THING_TYPE_ON_OFF_LIGHT.equals(thingTypeUID)) {
return new MagicOnOffLightHandler(thing);
}
if (THING_TYPE_DIMMABLE_LIGHT.equals(thingTypeUID)) {
} else if (THING_TYPE_DIMMABLE_LIGHT.equals(thingTypeUID)) {
return new MagicDimmableLightHandler(thing);
}
if (THING_TYPE_COLOR_LIGHT.equals(thingTypeUID)) {
} else if (THING_TYPE_COLOR_LIGHT.equals(thingTypeUID)) {
return new MagicColorLightHandler(thing);
}
if (THING_TYPE_CONTACT_SENSOR.equals(thingTypeUID)) {
} else if (THING_TYPE_CONTACT_SENSOR.equals(thingTypeUID)) {
return new MagicContactHandler(thing);
}
if (THING_TYPE_CONFIG_THING.equals(thingTypeUID)) {
} else if (THING_TYPE_CONFIG_THING.equals(thingTypeUID)) {
return new MagicConfigurableThingHandler(thing);
}
if (THING_TYPE_DELAYED_THING.equals(thingTypeUID)) {
} else if (THING_TYPE_DELAYED_THING.equals(thingTypeUID)) {
return new MagicDelayedOnlineHandler(thing);
}
if (THING_TYPE_LOCATION.equals(thingTypeUID)) {
} else if (THING_TYPE_LOCATION.equals(thingTypeUID)) {
return new MagicLocationThingHandler(thing);
}
if (THING_TYPE_THERMOSTAT.equals(thingTypeUID)) {
} else if (THING_TYPE_THERMOSTAT.equals(thingTypeUID)) {
return new MagicThermostatThingHandler(thing);
}
if (THING_TYPE_FIRMWARE_UPDATE.equals(thingTypeUID)) {
} else if (THING_TYPE_FIRMWARE_UPDATE.equals(thingTypeUID)) {
return new MagicFirmwareUpdateThingHandler(thing);
}
if (THING_TYPE_BRIDGED_THING.equals(thingTypeUID)) {
} else if (THING_TYPE_BRIDGED_THING.equals(thingTypeUID)) {
return new MagicBridgedThingHandler(thing);
}
if (THING_TYPE_CHATTY_THING.equals(thingTypeUID)) {
} else if (THING_TYPE_CHATTY_THING.equals(thingTypeUID)) {
return new MagicChattyThingHandler(thing);
}
if (THING_TYPE_ROLLERSHUTTER.equals(thingTypeUID)) {
return new MagicRolllershutterHandler(thing);
}
if (THING_TYPE_PLAYER.equals(thingTypeUID)) {
} else if (THING_TYPE_ROLLERSHUTTER.equals(thingTypeUID)) {
return new MagicRollershutterHandler(thing);
} else if (THING_TYPE_PLAYER.equals(thingTypeUID)) {
return new MagicPlayerHandler(thing);
}
if (THING_TYPE_IMAGE.equals(thingTypeUID)) {
} else if (THING_TYPE_IMAGE.equals(thingTypeUID)) {
return new MagicImageHandler(thing);
}
if (THING_TYPE_ACTION_MODULE.equals(thingTypeUID)) {
} else if (THING_TYPE_ACTION_MODULE.equals(thingTypeUID)) {
return new MagicActionModuleThingHandler(thing);
}
if (THING_TYPE_DYNAMIC_STATE_DESCRIPTION.equals(thingTypeUID)) {
} else if (THING_TYPE_DYNAMIC_STATE_DESCRIPTION.equals(thingTypeUID)) {
return new MagicDynamicStateDescriptionThingHandler(thing, commandDescriptionProvider,
stateDescriptionProvider);
}
if (THING_TYPE_ONLINE_OFFLINE.equals(thingTypeUID)) {
} else if (THING_TYPE_ONLINE_OFFLINE.equals(thingTypeUID)) {
return new MagicOnlineOfflineHandler(thing);
}
if (THING_TYPE_BRIDGE_1.equals(thingTypeUID) || THING_TYPE_BRIDGE_2.equals(thingTypeUID)) {
} else if (THING_TYPE_BRIDGE_1.equals(thingTypeUID) || THING_TYPE_BRIDGE_2.equals(thingTypeUID)) {
return new MagicBridgeHandler((Bridge) thing);
}

View File

@ -0,0 +1,117 @@
# binding
binding.magic.name = Magic Binding
binding.magic.description = This is the Magic binding for openHAB.
# thing types
thing-type.magic.action-module.label = Magic ActionModule Thing
thing-type.magic.action-module.description = A Thing with an ActionModule
thing-type.magic.bridgedThing.label = Magic Bridged Thing
thing-type.magic.bridgedThing.description = A magic bridged thing.
thing-type.magic.button.label = Magic Button
thing-type.magic.button.description = A button triggering different events.
thing-type.magic.chatty-thing.label = Magic ChattyThing
thing-type.magic.chatty-thing.description = A thing that periodically sends data.
thing-type.magic.chatty-thing.channel.number.label = Number to show
thing-type.magic.chatty-thing.channel.text.label = Text to show
thing-type.magic.color-light.label = Magic Light - Color
thing-type.magic.color-light.description = A dimmable light with changeable colors.
thing-type.magic.configurable-thing.label = Magic Configurable Thing
thing-type.magic.configurable-thing.description = A thing that can be configured.
thing-type.magic.contact-sensor.label = Magic Sensor - Door/Window Contact
thing-type.magic.contact-sensor.description = A door/window sensor indicating an open/close status.
thing-type.magic.delayed-thing.label = Magic Delayed Online Thing
thing-type.magic.delayed-thing.description = A thing that goes online after some time.
thing-type.magic.dimmable-light.label = Magic Light - Dimmable
thing-type.magic.dimmable-light.description = A dimmable light
thing-type.magic.dynamic-state-description.label = Magic DynamicStateDescription Thing
thing-type.magic.dynamic-state-description.description = A Thing with a DynamicStateDescription
thing-type.magic.extensible-thing.label = Magic Light - Extensible
thing-type.magic.extensible-thing.description = A generic light thing with extension channels
thing-type.magic.firmware-update.label = Magic Firmware Updatable Thing
thing-type.magic.firmware-update.description = A thing which allows updating its firmware
thing-type.magic.image.label = Magic Image
thing-type.magic.image.description = A thing providing an image
thing-type.magic.location-thing.label = Magic Location
thing-type.magic.location-thing.description = A location thing providing a location channel.
thing-type.magic.magic-bridge1.label = Magic Bridge 1
thing-type.magic.magic-bridge1.description = The 1st magic bridge
thing-type.magic.magic-bridge2.label = Magic Bridge 2
thing-type.magic.magic-bridge2.description = The 2nd magic bridge
thing-type.magic.online-offline.label = Magic Online Offline
thing-type.magic.online-offline.description = An online/offline toggle thing
thing-type.magic.onoff-light.label = Magic Light - On/Off
thing-type.magic.onoff-light.description = A on/off light
thing-type.magic.player.label = Magic Player Thing
thing-type.magic.player.description = A media player
thing-type.magic.rollershutter.label = Magic Rollershutter Thing
thing-type.magic.rollershutter.description = A rollershutter
thing-type.magic.thermostat.label = Magic Thermostat
thing-type.magic.thermostat.description = A thermostat for set point temperature and current temperature.
# thing types config
thing-type.config.magic.action-module.textParam.label = Text Parameter
thing-type.config.magic.action-module.textParam.description = Just a text
thing-type.config.magic.chattyConfig.interval.label = Interval
thing-type.config.magic.chattyConfig.interval.description = Interval to send data in seconds. (Use 0 to disable data sending)
thing-type.config.magic.config.interval.label = Integer
thing-type.config.magic.config.interval.description = Integer value between 1 and 100.
thing-type.config.magic.dynamic-state-description.textParam.label = Text Parameter
thing-type.config.magic.dynamic-state-description.textParam.description = Just a text
thing-type.config.magic.image.source.label = Image URL
thing-type.config.magic.image.source.description = The URL the image will be loaded from
thing-type.config.magic.online-offline.toggleTime.label = Toggle Time
thing-type.config.magic.online-offline.toggleTime.description = The time in seconds to toggle between ONLINE and OFFLINE status.
thing-type.config.magic.update-config.updateModel.label = Model ID
thing-type.config.magic.update-config.updateModel.description = The model of the magic firmware update thing
thing-type.config.magic.update-config.updateModel.option.Alohomora = Alohomora
thing-type.config.magic.update-config.updateModel.option.Colloportus = Colloportus
thing-type.config.magic.update-config.updateModel.option.Lumos = Lumos
thing-type.config.magic.update-config.updateModel.option.Nox = Nox
# channel types
channel-type.magic.alert.label = Alert
channel-type.magic.alert.description = The alert channel allows a temporary change to the bulbs state.
channel-type.magic.alert.command.option.NONE = None
channel-type.magic.alert.command.option.SELECT = Alert
channel-type.magic.alert.command.option.LSELECT = Long Alert
channel-type.magic.brightness.label = Dimmer
channel-type.magic.brightness.description = The dimmer channel allows to control the brightness.
channel-type.magic.choosy.label = Choosy
channel-type.magic.choosy.state.option.0 = Zero
channel-type.magic.choosy.state.option.1 = One
channel-type.magic.choosy.state.option.2 = Two
channel-type.magic.color.label = Color
channel-type.magic.color.description = The color channel allows to control the color of a light. It is also possible to dim values and switch the light on and off.
channel-type.magic.contact.label = Contact
channel-type.magic.image.label = Image
channel-type.magic.location.label = Location
channel-type.magic.number.label = Thing Online(>0)/Offline(<0) Delay
channel-type.magic.player.label = Player
channel-type.magic.rollershutter.label = Rollershutter
channel-type.magic.set-temperature.label = Set Point Temperature
channel-type.magic.switch.label = Switch
channel-type.magic.switch.description = The on/off channel allows to toggle between on and off.
channel-type.magic.systemcommand.label = Send system command
channel-type.magic.systemcommand.description = Sends a system command to Kodi. This allows to shutdown/suspend/hibernate/reboot/quit Kodi.
channel-type.magic.temperature.label = Current Temperature
channel-type.magic.text.label = Text channel
channel-type.magic.timestamp.label = Timestamp
channel-type.magic.trigger.label = Trigger
# channel types config
channel-type.config.magic.color.boostBlue.label = Blue boost
channel-type.config.magic.color.boostBlue.description = Boost the blue color channel (in percent)
channel-type.config.magic.color.boostGreen.label = Green boost
channel-type.config.magic.color.boostGreen.description = Boost the green color channel (in percent)
channel-type.config.magic.color.boostRed.label = Red boost
channel-type.config.magic.color.boostRed.description = Boost the red color channel (in percent)
channel-type.config.magic.switch.invert.label = Invert operation
# others
module.binding.magic.testMethod.label = Test method

View File

@ -1,15 +1,17 @@
channel-type.magic.alert.label = Alarm
channel-type.magic.alert.label = Alert
channel-type.magic.alert.description = Ermöglicht ein temporäres Blinken.
channel-type.magic.alert.state.option.NONE = Kein Blinken
channel-type.magic.alert.state.option.SELECT = Einmaliges Blinken
channel-type.magic.alert.state.option.LSELECT = Mehrfaches Blinken
channel-type.magic.alert.command.option.NONE = Kein Blinken
channel-type.magic.alert.command.option.SELECT = Einmaliges Blinken
channel-type.magic.alert.command.option.LSELECT = Mehrfaches Blinken
channel-type.magic.systemcommand.label = Systembefehl
channel-type.magic.systemcommand.description = Ermöglicht das Senden eines Systembefehls um das Kodi Media Center neu zu starten, in den Ruhezustand oder Stromsparmodus zu versetzen oder herunterzufahren.
channel-type.magic.systemcommand.state.option.Shutdown = Herunterfahren
channel-type.magic.systemcommand.state.option.Suspend = Bereitschaft
channel-type.magic.systemcommand.state.option.Hibernate = Ruhezustand
channel-type.magic.systemcommand.state.option.Reboot = Neustart
channel-type.magic.systemcommand.state.option.Quit = Verlassen
channel-type.magic.systemcommand.command.option.Shutdown = Herunterfahren
channel-type.magic.systemcommand.command.option.Suspend = Bereitschaft
channel-type.magic.systemcommand.command.option.Hibernate = Ruhezustand
channel-type.magic.systemcommand.command.option.Reboot = Neustart
channel-type.magic.systemcommand.command.option.Quit = Verlassen
# others
module.binding.magic.testMethod.label = Test Methode

View File

@ -1 +1,3 @@
# others
module.binding.magic.testMethod.label = Test method

View File

@ -101,13 +101,15 @@
<channel-type id="temperature">
<item-type>Number:Temperature</item-type>
<label>Current Temperature</label>
<category>temperature</category>
<state readOnly="true" pattern="%.1f %unit%"/>
</channel-type>
<channel-type id="set-temperature">
<item-type>Number:Temperature</item-type>
<label>Set Point</label>
<state readOnly="false" pattern="%.1f %unit%" min="12" max="38" step="0.5"/>
<label>Set Point Temperature</label>
<category>heating</category>
<state pattern="%.1f %unit%" min="12" max="38" step="0.5"/>
<autoUpdatePolicy>recommend</autoUpdatePolicy>
</channel-type>

View File

@ -11,6 +11,17 @@
</config-description>
</thing-type>
<thing-type id="button">
<label>Magic Button</label>
<description>A button triggering different events.</description>
<channels>
<channel typeId="system.rawbutton" id="rawbutton"/>
<channel typeId="system.button" id="button"/>
<channel typeId="system.rawrocker" id="rawrocker"/>
</channels>
</thing-type>
<thing-type id="onoff-light" extensible="alert">
<label>Magic Light - On/Off</label>
<description>A on/off light</description>
@ -88,11 +99,12 @@
<thing-type id="thermostat">
<label>Magic Thermostat</label>
<description>A thermostat for set point and current temperature.</description>
<description>A thermostat for set point temperature and current temperature.</description>
<channels>
<channel typeId="temperature" id="temperature"></channel>
<channel typeId="set-temperature" id="set-temperature"></channel>
<channel typeId="temperature" id="temperature"/>
<channel typeId="set-temperature" id="set-temperature"/>
<channel typeId="system.battery-level" id="battery-level"/>
</channels>
</thing-type>
@ -156,7 +168,7 @@
<label>Magic Rollershutter Thing</label>
<description>A rollershutter</description>
<channels>
<channel typeId="rollershutter" id="rollershutter"></channel>
<channel typeId="rollershutter" id="rollershutter"/>
</channels>
</thing-type>
@ -164,7 +176,7 @@
<label>Magic Player Thing</label>
<description>A media player</description>
<channels>
<channel typeId="player" id="player"></channel>
<channel typeId="player" id="player"/>
</channels>
</thing-type>
@ -172,7 +184,7 @@
<label>Magic Image</label>
<description>A thing providing an image</description>
<channels>
<channel typeId="image" id="image"></channel>
<channel typeId="image" id="image"/>
</channels>
<config-description>
<parameter name="source" type="text" required="true">
@ -187,7 +199,7 @@
<label>Magic ActionModule Thing</label>
<description>A Thing with an ActionModule</description>
<channels>
<channel typeId="switch" id="switch"></channel>
<channel typeId="switch" id="switch"/>
</channels>
<config-description>
<parameter name="textParam" type="text" required="true">