diff --git a/bundles/org.openhab.binding.somfytahoma/README.md b/bundles/org.openhab.binding.somfytahoma/README.md index fd41cd2a8..1613c6e9e 100644 --- a/bundles/org.openhab.binding.somfytahoma/README.md +++ b/bundles/org.openhab.binding.somfytahoma/README.md @@ -62,6 +62,7 @@ Please see the example below. |-------------------------------------------------------------------------------|------------------------------|-----------------------------------------------------------------------------------------------------------------------------| | bridge | N.A | bridge does not expose any channel | | gateway | status | status of your Tahoma gateway | +| gateway | scenarios | used to run the scenarios defined in the cloud portal | | gate | gate_command | used for controlling your gate (open, close, stop, pedestrian) | | gate | gate_state | get state of your gate (open, closed, pedestrian) | | gate | gate_position | get position (0-100%) of your gate (where supported) | @@ -120,6 +121,9 @@ Please see the example below. | myfox camera | shutter | controlling of the camera shutter | | myfox alarm | myfox_alarm_command | used for sending commands to Somfy Myfox alarm device | +To run a scenario inside a rule for example, the ID of the scenario will be required. +You can list all the scenarios IDs with the following console command: `somfytahoma scenarios`. + ### Remarks All things which have a RSSI (relative received signal) state, expose a channel "rssi". diff --git a/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/SomfyTahomaBindingConstants.java b/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/SomfyTahomaBindingConstants.java index 21f5ec2e0..87345342c 100644 --- a/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/SomfyTahomaBindingConstants.java +++ b/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/SomfyTahomaBindingConstants.java @@ -12,7 +12,11 @@ */ package org.openhab.binding.somfytahoma.internal; -import java.util.*; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.core.thing.ThingTypeUID; @@ -156,6 +160,7 @@ public class SomfyTahomaBindingConstants { // Gateway public static final String STATUS = "status"; + public static final String SCENARIOS = "scenarios"; // Roller shutter, Awning, Screen, Blind, Garage door, Window, Curtain public static final String CONTROL = "control"; diff --git a/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/SomfyTahomaHandlerFactory.java b/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/SomfyTahomaHandlerFactory.java index 90d6b9989..bf6c40bbd 100644 --- a/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/SomfyTahomaHandlerFactory.java +++ b/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/SomfyTahomaHandlerFactory.java @@ -16,7 +16,43 @@ import static org.openhab.binding.somfytahoma.internal.SomfyTahomaBindingConstan import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; -import org.openhab.binding.somfytahoma.internal.handler.*; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaActionGroupHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaAdjustableSlatsRollerShutterHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaAwningHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaBridgeHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaContactSensorHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaCurtainHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaDimmerLightHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaDockHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaDoorLockHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaElectricitySensorHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaExteriorHeatingSystemHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaExternalAlarmHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaGateHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaGatewayHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaHumiditySensorHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaInternalAlarmHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaLightSensorHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaMyfoxAlarmHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaMyfoxCameraHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaOccupancySensorHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaOnOffHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaOnOffHeatingSystemHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaPergolaHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaPodHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaRollerShutterHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaSilentRollerShutterHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaSirenHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaSmokeSensorHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaTemperatureSensorHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaThermostatHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaUnoRollerShutterHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaValveHeatingSystemHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaVenetianBlindHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaWaterSensorHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaWindowHandleHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaWindowHandler; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaZwaveHeatingSystemHandler; import org.openhab.core.io.net.http.HttpClientFactory; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.Thing; @@ -43,10 +79,13 @@ public class SomfyTahomaHandlerFactory extends BaseThingHandlerFactory { private final Logger logger = LoggerFactory.getLogger(SomfyTahomaHandlerFactory.class); private final HttpClientFactory httpClientFactory; + private final SomfyTahomaStateDescriptionOptionProvider stateDescriptionProvider; @Activate - public SomfyTahomaHandlerFactory(@Reference HttpClientFactory httpClientFactory) { + public SomfyTahomaHandlerFactory(@Reference HttpClientFactory httpClientFactory, + final @Reference SomfyTahomaStateDescriptionOptionProvider stateDescriptionProvider) { this.httpClientFactory = httpClientFactory; + this.stateDescriptionProvider = stateDescriptionProvider; } @Override @@ -64,7 +103,7 @@ public class SomfyTahomaHandlerFactory extends BaseThingHandlerFactory { if (thingTypeUID.equals(THING_TYPE_BRIDGE)) { return new SomfyTahomaBridgeHandler((Bridge) thing, httpClientFactory); } else if (thingTypeUID.equals(THING_TYPE_GATEWAY)) { - return new SomfyTahomaGatewayHandler(thing); + return new SomfyTahomaGatewayHandler(thing, stateDescriptionProvider); } else if (thingTypeUID.equals(THING_TYPE_ROLLERSHUTTER)) { return new SomfyTahomaRollerShutterHandler(thing); } else if (thingTypeUID.equals(THING_TYPE_ROLLERSHUTTER_SILENT)) { diff --git a/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/SomfyTahomaStateDescriptionOptionProvider.java b/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/SomfyTahomaStateDescriptionOptionProvider.java new file mode 100644 index 000000000..653b37ad2 --- /dev/null +++ b/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/SomfyTahomaStateDescriptionOptionProvider.java @@ -0,0 +1,50 @@ +/** + * 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.binding.somfytahoma.internal; + +import java.util.List; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.binding.BaseDynamicStateDescriptionProvider; +import org.openhab.core.thing.i18n.ChannelTypeI18nLocalizationService; +import org.openhab.core.thing.type.DynamicStateDescriptionProvider; +import org.openhab.core.types.StateOption; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +/** + * Dynamic provider of state options while leaving other state description fields as original. + * + * @author Laurent Garnier - Initial contribution + */ +@Component(service = { DynamicStateDescriptionProvider.class, SomfyTahomaStateDescriptionOptionProvider.class }) +@NonNullByDefault +public class SomfyTahomaStateDescriptionOptionProvider extends BaseDynamicStateDescriptionProvider { + + public @Nullable List getStateOptions(ChannelUID channelUID) { + return channelOptionsMap.get(channelUID); + } + + @Reference + protected void setChannelTypeI18nLocalizationService( + final ChannelTypeI18nLocalizationService channelTypeI18nLocalizationService) { + this.channelTypeI18nLocalizationService = channelTypeI18nLocalizationService; + } + + protected void unsetChannelTypeI18nLocalizationService( + final ChannelTypeI18nLocalizationService channelTypeI18nLocalizationService) { + this.channelTypeI18nLocalizationService = null; + } +} diff --git a/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/console/SomfyTahomaCommandExtension.java b/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/console/SomfyTahomaCommandExtension.java new file mode 100644 index 000000000..6fd96fe91 --- /dev/null +++ b/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/console/SomfyTahomaCommandExtension.java @@ -0,0 +1,95 @@ +/** + * 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.binding.somfytahoma.internal.console; + +import java.util.List; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.somfytahoma.internal.handler.SomfyTahomaBridgeHandler; +import org.openhab.binding.somfytahoma.internal.model.SomfyTahomaActionGroup; +import org.openhab.core.io.console.Console; +import org.openhab.core.io.console.extensions.AbstractConsoleCommandExtension; +import org.openhab.core.io.console.extensions.ConsoleCommandExtension; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingRegistry; +import org.openhab.core.thing.ThingUID; +import org.openhab.core.thing.binding.ThingHandler; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +/** + * The {@link SomfyTahomaCommandExtension} is responsible for handling console commands + * + * @author Laurent Garnier - Initial contribution + */ + +@NonNullByDefault +@Component(service = ConsoleCommandExtension.class) +public class SomfyTahomaCommandExtension extends AbstractConsoleCommandExtension { + + private static final String SCENARIOS = "scenarios"; + + private final ThingRegistry thingRegistry; + + @Activate + public SomfyTahomaCommandExtension(final @Reference ThingRegistry thingRegistry) { + super("somfytahoma", "Interact with the Somfy Tahoma binding."); + this.thingRegistry = thingRegistry; + } + + @Override + public void execute(String[] args, Console console) { + if (args.length == 2) { + Thing thing = null; + try { + ThingUID thingUID = new ThingUID(args[0]); + thing = thingRegistry.get(thingUID); + } catch (IllegalArgumentException e) { + thing = null; + } + ThingHandler thingHandler = null; + SomfyTahomaBridgeHandler bridgeHandler = null; + if (thing != null) { + thingHandler = thing.getHandler(); + if (thingHandler instanceof SomfyTahomaBridgeHandler) { + bridgeHandler = (SomfyTahomaBridgeHandler) thingHandler; + } + } + if (thing == null) { + console.println("Bad thing id '" + args[0] + "'"); + printUsage(console); + } else if (thingHandler == null) { + console.println("No handler initialized for the thingUID '" + args[0] + "'"); + printUsage(console); + } else if (bridgeHandler == null) { + console.println("'" + args[0] + "' is not a Somfy Tahoma bridgeUID"); + printUsage(console); + } else if (args[1].equals(SCENARIOS)) { + for (SomfyTahomaActionGroup actionGroup : bridgeHandler.listActionGroups()) { + console.println("Id is \"" + actionGroup.getOid() + "\" for the scenario \"" + + actionGroup.getLabel() + "\""); + } + } else { + printUsage(console); + } + } else { + printUsage(console); + } + } + + @Override + public List getUsages() { + return List.of(buildCommandUsage(" " + SCENARIOS, "list all the scenarios with their id")); + } +} diff --git a/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/handler/SomfyTahomaGatewayHandler.java b/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/handler/SomfyTahomaGatewayHandler.java index 9bab4cebe..42277c8a0 100644 --- a/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/handler/SomfyTahomaGatewayHandler.java +++ b/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/handler/SomfyTahomaGatewayHandler.java @@ -12,17 +12,26 @@ */ package org.openhab.binding.somfytahoma.internal.handler; -import static org.openhab.binding.somfytahoma.internal.SomfyTahomaBindingConstants.STATUS; +import static org.openhab.binding.somfytahoma.internal.SomfyTahomaBindingConstants.*; import static org.openhab.core.thing.Thing.PROPERTY_FIRMWARE_VERSION; +import java.util.ArrayList; +import java.util.List; + import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.somfytahoma.internal.SomfyTahomaStateDescriptionOptionProvider; +import org.openhab.binding.somfytahoma.internal.model.SomfyTahomaActionGroup; import org.openhab.binding.somfytahoma.internal.model.SomfyTahomaStatus; import org.openhab.core.library.types.StringType; import org.openhab.core.thing.Channel; +import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.Thing; import org.openhab.core.thing.ThingStatus; import org.openhab.core.thing.ThingStatusDetail; +import org.openhab.core.types.Command; +import org.openhab.core.types.RefreshType; +import org.openhab.core.types.StateOption; /** * The {@link SomfyTahomaGatewayHandler} is responsible for handling commands, @@ -33,8 +42,11 @@ import org.openhab.core.thing.ThingStatusDetail; @NonNullByDefault public class SomfyTahomaGatewayHandler extends SomfyTahomaBaseThingHandler { - public SomfyTahomaGatewayHandler(Thing thing) { + private final SomfyTahomaStateDescriptionOptionProvider stateDescriptionProvider; + + public SomfyTahomaGatewayHandler(Thing thing, SomfyTahomaStateDescriptionOptionProvider stateDescriptionProvider) { super(thing); + this.stateDescriptionProvider = stateDescriptionProvider; } @Override @@ -42,6 +54,7 @@ public class SomfyTahomaGatewayHandler extends SomfyTahomaBaseThingHandler { if (bridgeStatus != null) { if (bridgeStatus == ThingStatus.ONLINE) { refresh(STATUS); + refresh(SCENARIOS); } else { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE); } @@ -52,21 +65,46 @@ public class SomfyTahomaGatewayHandler extends SomfyTahomaBaseThingHandler { @Override public void refresh(String channel) { - String id = getGateWayId(); - SomfyTahomaStatus status = getTahomaStatus(id); - String tahomaStatus = status.getStatus(); - Channel ch = thing.getChannel(channel); - if (ch != null) { - updateState(ch.getUID(), new StringType(tahomaStatus)); - } - // update the firmware property - String fw = status.getProtocolVersion(); - updateProperty(PROPERTY_FIRMWARE_VERSION, fw); + if (channel.equals(STATUS)) { + String id = getGateWayId(); + SomfyTahomaStatus status = getTahomaStatus(id); + String tahomaStatus = status.getStatus(); + Channel ch = thing.getChannel(channel); + if (ch != null) { + updateState(ch.getUID(), new StringType(tahomaStatus)); + } + // update the firmware property + String fw = status.getProtocolVersion(); + updateProperty(PROPERTY_FIRMWARE_VERSION, fw); - updateStatus("DISCONNECTED".equals(tahomaStatus) ? ThingStatus.OFFLINE : ThingStatus.ONLINE); + updateStatus("DISCONNECTED".equals(tahomaStatus) ? ThingStatus.OFFLINE : ThingStatus.ONLINE); + } else if (channel.equals(SCENARIOS)) { + SomfyTahomaBridgeHandler handler = getBridgeHandler(); + if (handler != null) { + List options = new ArrayList<>(); + for (SomfyTahomaActionGroup actionGroup : handler.listActionGroups()) { + options.add(new StateOption(actionGroup.getOid(), actionGroup.getLabel())); + } + stateDescriptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), channel), options); + } + } } public String getGateWayId() { return getThing().getConfiguration().get("id").toString(); } + + @Override + public void handleCommand(ChannelUID channelUID, Command command) { + super.handleCommand(channelUID, command); + if (command instanceof RefreshType) { + return; + } + if (channelUID.getId().equals(SCENARIOS)) { + SomfyTahomaBridgeHandler handler = getBridgeHandler(); + if (handler != null && command instanceof StringType) { + handler.executeActionGroup(command.toString()); + } + } + } } diff --git a/bundles/org.openhab.binding.somfytahoma/src/main/resources/OH-INF/thing/channels.xml b/bundles/org.openhab.binding.somfytahoma/src/main/resources/OH-INF/thing/channels.xml index 934e625fb..4f20b1c23 100644 --- a/bundles/org.openhab.binding.somfytahoma/src/main/resources/OH-INF/thing/channels.xml +++ b/bundles/org.openhab.binding.somfytahoma/src/main/resources/OH-INF/thing/channels.xml @@ -389,4 +389,11 @@ Operating mode of the Somfy thermostatic valve + + + String + + The scenarios defined in the cloud portal + recommend + diff --git a/bundles/org.openhab.binding.somfytahoma/src/main/resources/OH-INF/thing/gateway.xml b/bundles/org.openhab.binding.somfytahoma/src/main/resources/OH-INF/thing/gateway.xml index 8861601a6..62dffd42b 100644 --- a/bundles/org.openhab.binding.somfytahoma/src/main/resources/OH-INF/thing/gateway.xml +++ b/bundles/org.openhab.binding.somfytahoma/src/main/resources/OH-INF/thing/gateway.xml @@ -11,6 +11,7 @@ + id