[somfytahoma] New channel on the gateway to execute scenes (#10346)

* [somfytahoma] New channel on the bridge to execute scenes

Signed-off-by: Laurent Garnier <lg.hc@free.fr>

* Review comment: documentation updated

Signed-off-by: Laurent Garnier <lg.hc@free.fr>

* Console command added to list the scenarios IDs

Signed-off-by: Laurent Garnier <lg.hc@free.fr>

* Update state of new channel

Signed-off-by: Laurent Garnier <lg.hc@free.fr>

* Review comment: set auto update policy to recommend

Signed-off-by: Laurent Garnier <lg./hc@free.fr>
This commit is contained in:
lolodomo 2021-04-03 13:35:02 +02:00 committed by GitHub
parent 4ff238d3f4
commit 3525c9123e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 256 additions and 17 deletions

View File

@ -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 <bridgeUID> scenarios`.
### Remarks
All things which have a RSSI (relative received signal) state, expose a channel "rssi".

View File

@ -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";

View File

@ -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)) {

View File

@ -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<StateOption> 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;
}
}

View File

@ -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<String> getUsages() {
return List.of(buildCommandUsage("<bridgeUID> " + SCENARIOS, "list all the scenarios with their id"));
}
}

View File

@ -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<StateOption> 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());
}
}
}
}

View File

@ -389,4 +389,11 @@
<description>Operating mode of the Somfy thermostatic valve</description>
<state readOnly="true"/>
</channel-type>
<channel-type id="scenarios">
<item-type>String</item-type>
<label>Scenarios</label>
<description>The scenarios defined in the cloud portal</description>
<autoUpdatePolicy>recommend</autoUpdatePolicy>
</channel-type>
</thing:thing-descriptions>

View File

@ -11,6 +11,7 @@
<label>Somfy Tahoma Gateway</label>
<channels>
<channel id="status" typeId="status"></channel>
<channel id="scenarios" typeId="scenarios"></channel>
</channels>
<representation-property>id</representation-property>
<config-description-ref uri="thing-type:somfytahoma:gateway"/>