[smsmodem] Initial contribution (#12250)

* [smsmodem] Initial contribution

This binding connects to a USB serial GSM modem (or a network exposed one, a.k.a ser2net) and allows openHAB to send and receive SMS through it.

Signed-off-by: Gwendal Roulleau <gwendal.roulleau@gmail.com>

* [smsmodem] README fix

Signed-off-by: Gwendal Roulleau <gwendal.roulleau@gmail.com>

* [smsmodem] build/spotless fix

Signed-off-by: Gwendal Roulleau <gwendal.roulleau@gmail.com>

* [smsmodem] compliance with 3rd party license

And long running thread naming convention
And treated some code warning 

Signed-off-by: Gwendal Roulleau <gwendal.roulleau@gmail.com>

* [smsmodem] i18n

Signed-off-by: Gwendal Roulleau <gwendal.roulleau@gmail.com>

* [smsmodem] Small fixes

update channel
rename action to avoid colision with other binding and a too generic name

Signed-off-by: Gwendal Roulleau <gwendal.roulleau@gmail.com>

* [smsmodem] Use of standard Thing properties

Signed-off-by: Gwendal Roulleau <gwendal.roulleau@gmail.com>

* [smsmodem] Fix sender identifier error with special character

Signed-off-by: Gwendal Roulleau <gwendal.roulleau@gmail.com>

* [smsmodem] Add encoding parameter

For non latin character in SMS

Signed-off-by: Gwendal Roulleau <gwendal.roulleau@gmail.com>

* [smsmodem] Apply review

Signed-off-by: Gwendal Roulleau <gwendal.roulleau@gmail.com>

* [smsmodem] Split local and remote modem in two thing-types

Signed-off-by: Gwendal Roulleau <gwendal.roulleau@gmail.com>

* [smsmodem] Apply review

Signed-off-by: Gwendal Roulleau <gwendal.roulleau@gmail.com>

* [smsmodem] Apply review

Signed-off-by: Gwendal Roulleau <gwendal.roulleau@gmail.com>

* [smsmodem] Apply code review (removing unnecessary method)

Signed-off-by: Gwendal Roulleau <gwendal.roulleau@gmail.com>

Signed-off-by: Gwendal Roulleau <gwendal.roulleau@gmail.com>
Co-authored-by: Gwendal Roulleau <gwendal.roulleau@gmail.com>
This commit is contained in:
Gwendal Roulleau
2022-12-03 21:35:30 +01:00
committed by GitHub
parent 3e068ed431
commit 56728b6091
58 changed files with 7413 additions and 1 deletions

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.smsmodem-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
<feature name="openhab-binding-smsmodem" description="SMSModem Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<feature>openhab-transport-serial</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.smsmodem/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,28 @@
/**
* Copyright (c) 2010-2022 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.smsmodem.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link SMSConversationConfiguration} class contains fields mapping thing configuration parameters.
*
* @author Gwendal ROULLEAU - Initial contribution
*/
@NonNullByDefault
public class SMSConversationConfiguration {
public String recipient = "";
public boolean deliveryReport = false;
public String encoding = "Enc7";
}

View File

@@ -0,0 +1,98 @@
/**
* Copyright (c) 2010-2022 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.smsmodem.internal;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.smsmodem.internal.handler.SMSConversationHandler;
import org.openhab.binding.smsmodem.internal.handler.SMSModemBridgeHandler;
import org.openhab.core.config.discovery.AbstractDiscoveryService;
import org.openhab.core.config.discovery.DiscoveryResult;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.config.discovery.DiscoveryService;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
/**
* This class implements a discovery service for SMSConversation
*
* @author Gwendal ROULLEAU - Initial contribution
*/
@NonNullByDefault
public class SMSConversationDiscoveryService extends AbstractDiscoveryService
implements DiscoveryService, ThingHandlerService {
private @NonNullByDefault({}) SMSModemBridgeHandler bridgeHandler;
private @NonNullByDefault({}) ThingUID bridgeUid;
public SMSConversationDiscoveryService() {
super(0);
}
public SMSConversationDiscoveryService(int timeout) throws IllegalArgumentException {
super(timeout);
}
@Override
protected void startScan() {
for (String msisdn : bridgeHandler.getAllSender()) {
buildDiscovery(msisdn);
}
}
public void buildDiscovery(String sender) {
String senderSanitized = sender.replaceAll("[^a-zA-Z0-9+]", "_");
ThingUID thingUID = new ThingUID(SMSModemBindingConstants.SMSCONVERSATION_THING_TYPE, senderSanitized,
bridgeUid.getId());
DiscoveryResult result = DiscoveryResultBuilder.create(thingUID)
.withProperty(SMSModemBindingConstants.SMSCONVERSATION_PARAMETER_RECIPIENT, senderSanitized)
.withLabel("Conversation with " + sender).withBridge(bridgeUid)
.withThingType(SMSModemBindingConstants.SMSCONVERSATION_THING_TYPE)
.withRepresentationProperty(SMSModemBindingConstants.SMSCONVERSATION_PARAMETER_RECIPIENT).build();
thingDiscovered(result);
}
public void buildByAutoDiscovery(String sender) {
if (isBackgroundDiscoveryEnabled()) {
buildDiscovery(sender);
}
}
@Override
public Set<ThingTypeUID> getSupportedThingTypes() {
return Set.of(SMSConversationHandler.SUPPORTED_THING_TYPES_UIDS);
}
@Override
public void setThingHandler(ThingHandler handler) {
this.bridgeHandler = (SMSModemBridgeHandler) handler;
this.bridgeUid = handler.getThing().getUID();
this.bridgeHandler.setDiscoveryService(this);
}
@Override
public @Nullable ThingHandler getThingHandler() {
return bridgeHandler;
}
@Override
public void deactivate() {
super.deactivate();
}
}

View File

@@ -0,0 +1,57 @@
/**
* Copyright (c) 2010-2022 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.smsmodem.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link SMSModemBindingConstants} class defines common constants, which are
* used across the whole binding.
*
* @author Gwendal ROULLEAU - Initial contribution
*/
@NonNullByDefault
public class SMSModemBindingConstants {
private static final String BINDING_ID = "smsmodem";
// List of all Thing Type UIDs
public static final ThingTypeUID SMSCONVERSATION_THING_TYPE = new ThingTypeUID(BINDING_ID, "smsconversation");
public static final ThingTypeUID SMSMODEMBRIDGE_THING_TYPE = new ThingTypeUID(BINDING_ID, "smsmodembridge");
public static final ThingTypeUID SMSMODEMREMOTEBRIDGE_THING_TYPE = new ThingTypeUID(BINDING_ID,
"smsmodemremotebridge");
// List of all Channel ids
public static final String CHANNEL_RECEIVED = "receive";
public static final String CHANNEL_SEND = "send";
public static final String CHANNEL_DELIVERYSTATUS = "deliverystatus";
public static final String CHANNEL_TRIGGER_MODEM_RECEIVE = "receivetrigger";
// parameter
public static final String SMSCONVERSATION_PARAMETER_RECIPIENT = "recipient";
// List of all properties
public static final String PROPERTY_MANUFACTURER = Thing.PROPERTY_VENDOR;
public static final String PROPERTY_MODEL = Thing.PROPERTY_MODEL_ID;
public static final String PROPERTY_SWVERSION = Thing.PROPERTY_FIRMWARE_VERSION;
public static final String PROPERTY_SERIALNO = Thing.PROPERTY_SERIAL_NUMBER;
public static final String PROPERTY_IMSI = "imsi";
public static final String PROPERTY_RSSI = "rssi";
public static final String PROPERTY_MODE = "mode";
public static final String PROPERTY_TOTALSENT = "sent";
public static final String PROPERTY_TOTALFAILED = "failed";
public static final String PROPERTY_TOTALRECEIVED = "received";
public static final String PROPERTY_TOTALFAILURE = "failure";
}

View File

@@ -0,0 +1,30 @@
/**
* Copyright (c) 2010-2022 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.smsmodem.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link SMSModemBridgeConfiguration} class contains fields mapping bridge configuration parameters.
*
* @author Gwendal ROULLEAU - Initial contribution
*/
@NonNullByDefault
public class SMSModemBridgeConfiguration {
public String serialPort = "";
public Integer baud = 9600;
public String simPin = "";
public Integer pollingInterval = 15;
public Integer delayBetweenSend = 0;
}

View File

@@ -0,0 +1,76 @@
/**
* Copyright (c) 2010-2022 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.smsmodem.internal;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.smsmodem.internal.handler.SMSConversationHandler;
import org.openhab.binding.smsmodem.internal.handler.SMSModemBridgeHandler;
import org.openhab.core.io.transport.serial.SerialPortManager;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
/**
* The {@link SMSModemHandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Gwendal ROULLEAU - Initial contribution
*/
@Component(configurationPid = "binding.smsmodem", service = ThingHandlerFactory.class)
@NonNullByDefault
public class SMSModemHandlerFactory extends BaseThingHandlerFactory {
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = new HashSet<>();
{
SUPPORTED_THING_TYPES_UIDS.add(SMSConversationHandler.SUPPORTED_THING_TYPES_UIDS);
SUPPORTED_THING_TYPES_UIDS.addAll(SMSModemBridgeHandler.SUPPORTED_THING_TYPES_UIDS);
}
private @NonNullByDefault({}) SerialPortManager serialPortManager;
@Reference
protected void setSerialPortManager(final SerialPortManager serialPortManager) {
this.serialPortManager = serialPortManager;
}
protected void unsetSerialPortManager(final SerialPortManager serialPortManager) {
this.serialPortManager = null;
}
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}
@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (SMSModemBridgeHandler.SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID)) {
return new SMSModemBridgeHandler((Bridge) thing, serialPortManager);
} else if (SMSConversationHandler.SUPPORTED_THING_TYPES_UIDS.equals(thingTypeUID)) {
return new SMSConversationHandler(thing);
}
return null;
}
}

View File

@@ -0,0 +1,30 @@
/**
* Copyright (c) 2010-2022 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.smsmodem.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link SMSModemRemoteBridgeConfiguration} class contains fields mapping bridge configuration parameters.
*
* @author Gwendal ROULLEAU - Initial contribution
*/
@NonNullByDefault
public class SMSModemRemoteBridgeConfiguration {
public String ip = "";
public Integer networkPort = 2000;
public String simPin = "";
public Integer pollingInterval = 15;
public Integer delayBetweenSend = 0;
}

View File

@@ -0,0 +1,81 @@
/**
* Copyright (c) 2010-2022 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.smsmodem.internal.actions;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.smsmodem.internal.handler.SMSModemBridgeHandler;
import org.openhab.core.automation.annotation.ActionInput;
import org.openhab.core.automation.annotation.RuleAction;
import org.openhab.core.thing.binding.ThingActions;
import org.openhab.core.thing.binding.ThingActionsScope;
import org.openhab.core.thing.binding.ThingHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.smslib.message.AbstractMessage.Encoding;
/**
* The {@link SMSModemActions} exposes some actions
*
* @author Gwendal ROULLEAU - Initial contribution
*/
@ThingActionsScope(name = "smsmodem")
@NonNullByDefault
public class SMSModemActions implements ThingActions {
private @NonNullByDefault({}) SMSModemBridgeHandler handler;
private final Logger logger = LoggerFactory.getLogger(SMSModemActions.class);
@Override
public void setThingHandler(@Nullable ThingHandler handler) {
this.handler = (SMSModemBridgeHandler) handler;
}
@Override
public @Nullable ThingHandler getThingHandler() {
return handler;
}
@RuleAction(label = "Send Message With Special Encoding", description = "Send a message and specify encoding")
public void sendSMS(
@ActionInput(name = "recipient", label = "recipient", description = "Recipient of the message") @Nullable String recipient,
@ActionInput(name = "message", label = "message", description = "Message to send") @Nullable String message,
@ActionInput(name = "encoding", label = "encoding", description = "Encoding") @Nullable String encoding) {
if (recipient != null && !recipient.isEmpty() && message != null) {
handler.send(recipient, message, false, encoding);
} else {
logger.warn("SMSModem cannot send a message with no recipient or text");
}
}
@RuleAction(label = "Send Message", description = "Send a message")
public void sendSMS(
@ActionInput(name = "recipient", label = "recipient", description = "Recipient of the message") @Nullable String recipient,
@ActionInput(name = "message", label = "message", description = "Message to send") @Nullable String message) {
sendSMS(recipient, message, Encoding.Enc7.toString());
}
public static void sendSMS(@Nullable ThingActions actions, @Nullable String recipient, @Nullable String message,
@Nullable String encoding) {
if (actions instanceof SMSModemActions) {
((SMSModemActions) actions).sendSMS(recipient, message, encoding);
} else {
throw new IllegalArgumentException("Instance is not an SMSModemActions class.");
}
}
public static void sendSMS(@Nullable ThingActions actions, @Nullable String recipient, @Nullable String message) {
sendSMS(actions, recipient, message, Encoding.Enc7.toString());
}
}

View File

@@ -0,0 +1,32 @@
/**
* Copyright (c) 2010-2022 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.smsmodem.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
*
* DeliveryStatus enum for delivery report status
*
* @author Gwendal ROULLEAU - Initial contribution
*/
@NonNullByDefault
public enum DeliveryStatus {
UNKNOWN,
QUEUED,
SENT,
PENDING,
DELIVERED,
EXPIRED,
FAILED
}

View File

@@ -0,0 +1,35 @@
/**
* Copyright (c) 2010-2022 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.smsmodem.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
*
* Exception class for SMSLib configuration
*
* @author Gwendal ROULLEAU - Initial contribution
*/
@NonNullByDefault
public class ModemConfigurationException extends Exception {
private static final long serialVersionUID = -3455806333751297448L;
public ModemConfigurationException(String message) {
super(message);
}
public ModemConfigurationException(String message, Exception cause) {
super(message, cause);
}
}

View File

@@ -0,0 +1,123 @@
/**
* Copyright (c) 2010-2022 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.smsmodem.internal.handler;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.smsmodem.internal.SMSConversationConfiguration;
import org.openhab.binding.smsmodem.internal.SMSModemBindingConstants;
import org.openhab.core.i18n.ConfigurationException;
import org.openhab.core.library.types.StringType;
import org.openhab.core.thing.Bridge;
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.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link SMSConversationHandler} is responsible for managing
* discussion channels.
*
* @author Gwendal ROULLEAU - Initial contribution
*/
@NonNullByDefault
public class SMSConversationHandler extends BaseThingHandler {
public static final ThingTypeUID SUPPORTED_THING_TYPES_UIDS = SMSModemBindingConstants.SMSCONVERSATION_THING_TYPE;
private final Logger logger = LoggerFactory.getLogger(SMSConversationHandler.class);
private @Nullable SMSModemBridgeHandler bridgeHandler;
private SMSConversationConfiguration config;
public SMSConversationHandler(Thing thing) {
super(thing);
this.config = new SMSConversationConfiguration();
}
public String getRecipient() {
return config.recipient.trim();
}
private synchronized void checkBridgeHandler() {
if (this.bridgeHandler == null) {
Bridge bridge = getBridge();
if (bridge == null) {
throw new ConfigurationException("Required bridge not defined for SMSconversation {} with {}.",
thing.getUID(), getRecipient());
}
ThingHandler handler = bridge.getHandler();
if (handler instanceof SMSModemBridgeHandler) {
this.bridgeHandler = (SMSModemBridgeHandler) handler;
} else {
throw new ConfigurationException("No available bridge handler found for SMSConversation {} bridge {} .",
thing.getUID(), bridge.getUID());
}
}
}
protected void checkAndReceive(String sender, String text) {
String conversationRecipient = config.recipient.trim();
// is the recipient the one handled by this conversation ? :
if (conversationRecipient.equals(sender)) {
updateState(SMSModemBindingConstants.CHANNEL_RECEIVED, new StringType(text));
}
}
protected void checkAndUpdateDeliveryStatus(String messageRecipient, DeliveryStatus sentStatus) {
String conversationRecipient = config.recipient.trim();
// is the recipient the one handled by this conversation ? :
if (conversationRecipient.equals(messageRecipient)) {
updateState(SMSModemBindingConstants.CHANNEL_DELIVERYSTATUS, new StringType(sentStatus.name()));
}
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof RefreshType) {
return;
}
if (channelUID.getId().equals(SMSModemBindingConstants.CHANNEL_SEND)) {
send(command.toString());
updateState(SMSModemBindingConstants.CHANNEL_SEND, new StringType(command.toString()));
}
}
public void send(String text) {
SMSModemBridgeHandler bridgeHandlerFinal = bridgeHandler;
if (bridgeHandlerFinal != null) {
bridgeHandlerFinal.send(getRecipient(), text, config.deliveryReport, config.encoding);
} else {
logger.warn("Only channel 'send' in SMSConversation can receive command");
}
}
@Override
public void initialize() {
config = getConfigAs(SMSConversationConfiguration.class);
try {
checkBridgeHandler();
updateStatus(ThingStatus.ONLINE);
} catch (ConfigurationException confe) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, confe.getMessage());
}
}
}

View File

@@ -0,0 +1,492 @@
/**
* Copyright (c) 2010-2022 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.smsmodem.internal.handler;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.smsmodem.internal.SMSConversationDiscoveryService;
import org.openhab.binding.smsmodem.internal.SMSModemBindingConstants;
import org.openhab.binding.smsmodem.internal.SMSModemBridgeConfiguration;
import org.openhab.binding.smsmodem.internal.SMSModemRemoteBridgeConfiguration;
import org.openhab.binding.smsmodem.internal.actions.SMSModemActions;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.io.transport.serial.SerialPortIdentifier;
import org.openhab.core.io.transport.serial.SerialPortManager;
import org.openhab.core.thing.Bridge;
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.thing.ThingTypeUID;
import org.openhab.core.thing.binding.BaseBridgeHandler;
import org.openhab.core.thing.binding.ThingHandlerService;
import org.openhab.core.types.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.smslib.CommunicationException;
import org.smslib.Modem;
import org.smslib.Modem.Status;
import org.smslib.callback.IDeviceInformationListener;
import org.smslib.callback.IInboundOutboundMessageListener;
import org.smslib.callback.IModemStatusListener;
import org.smslib.message.AbstractMessage.Encoding;
import org.smslib.message.DeliveryReportMessage;
import org.smslib.message.InboundMessage;
import org.smslib.message.MsIsdn;
import org.smslib.message.OutboundMessage;
import org.smslib.message.Payload;
import org.smslib.message.Payload.Type;
/**
* The {@link SMSModemBridgeHandler} is responsible for handling
* communication with the modem.
*
* @author Gwendal ROULLEAU - Initial contribution
*/
@NonNullByDefault
public class SMSModemBridgeHandler extends BaseBridgeHandler
implements IModemStatusListener, IInboundOutboundMessageListener, IDeviceInformationListener {
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(
SMSModemBindingConstants.SMSMODEMBRIDGE_THING_TYPE,
SMSModemBindingConstants.SMSMODEMREMOTEBRIDGE_THING_TYPE);
private final Logger logger = LoggerFactory.getLogger(SMSModemBridgeHandler.class);
private SerialPortManager serialPortManager;
/**
* The smslib object responsible for the serial communication with the modem
*/
private @Nullable Modem modem;
/**
* A scheduled watchdog check
*/
private @Nullable ScheduledFuture<?> checkScheduled;
// we keep a list of msisdn sender for autodiscovery
private Set<String> senderMsisdn = new HashSet<String>();
private @Nullable SMSConversationDiscoveryService discoveryService;
private boolean shouldRun = false;
public SMSModemBridgeHandler(Bridge bridge, SerialPortManager serialPortManager) {
super(bridge);
this.serialPortManager = serialPortManager;
}
@Override
public void dispose() {
shouldRun = false;
ScheduledFuture<?> checkScheduledFinal = checkScheduled;
if (checkScheduledFinal != null) {
checkScheduledFinal.cancel(true);
}
Modem finalModem = modem;
if (finalModem != null) {
scheduler.execute(finalModem::stop);
finalModem.registerStatusListener(null);
finalModem.registerMessageListener(null);
finalModem.registerInformationListener(null);
}
modem = null;
}
@Override
protected void updateConfiguration(Configuration configuration) {
super.updateConfiguration(configuration);
scheduler.execute(() -> {
Modem finalModem = modem;
if (finalModem != null) {
finalModem.stop();
}
checkAndStartModemIfNeeded();
});
}
@Override
public void initialize() {
updateStatus(ThingStatus.UNKNOWN);
shouldRun = true;
ScheduledFuture<?> checkScheduledFinal = checkScheduled;
if (checkScheduledFinal == null || (checkScheduledFinal.isDone()) && this.shouldRun) {
checkScheduled = scheduler.scheduleWithFixedDelay(this::checkAndStartModemIfNeeded, 0, 15,
TimeUnit.SECONDS);
}
}
private synchronized void checkAndStartModemIfNeeded() {
try {
if (shouldRun && !isRunning()) {
logger.debug("Initializing smsmodem");
// ensure the underlying modem is stopped before trying to (re)starting it :
Modem finalModem = modem;
if (finalModem != null) {
finalModem.stop();
}
String logName;
if (getThing().getThingTypeUID().equals(SMSModemBindingConstants.SMSMODEMBRIDGE_THING_TYPE)) {
SMSModemBridgeConfiguration config = getConfigAs(SMSModemBridgeConfiguration.class);
modem = new Modem(serialPortManager, resolveEventualSymbolicLink(config.serialPort),
Integer.valueOf(config.baud), config.simPin, scheduler, config.pollingInterval,
config.delayBetweenSend);
checkParam(config);
logName = config.serialPort + " | " + config.baud;
} else if (getThing().getThingTypeUID()
.equals(SMSModemBindingConstants.SMSMODEMREMOTEBRIDGE_THING_TYPE)) {
SMSModemRemoteBridgeConfiguration config = getConfigAs(SMSModemRemoteBridgeConfiguration.class);
modem = new Modem(serialPortManager, resolveEventualSymbolicLink(config.ip),
Integer.valueOf(config.networkPort), config.simPin, scheduler, config.pollingInterval,
config.delayBetweenSend);
checkRemoteParam(config);
logName = config.ip + ":" + config.networkPort;
} else {
throw new IllegalArgumentException("Invalid thing type");
}
logger.debug("Now trying to start SMSModem {}", logName);
finalModem = modem;
if (finalModem != null) {
finalModem.registerStatusListener(this);
finalModem.registerMessageListener(this);
finalModem.registerInformationListener(this);
finalModem.start();
}
logger.debug("SMSModem {} started", logName);
}
} catch (ModemConfigurationException e) {
String message = e.getMessage();
if (e.getCause() != null && e.getCause() instanceof IOException) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, message);
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, message);
}
}
}
private void checkParam(SMSModemBridgeConfiguration config) throws ModemConfigurationException {
String realSerialPort = resolveEventualSymbolicLink(config.serialPort);
SerialPortIdentifier identifier = serialPortManager.getIdentifier(realSerialPort);
if (identifier == null) {
// no serial port
throw new ModemConfigurationException(
realSerialPort + " with " + config.baud + " is not a valid serial port | baud");
}
}
private void checkRemoteParam(SMSModemRemoteBridgeConfiguration config) throws ModemConfigurationException {
try {
InetAddress inetAddress = InetAddress.getByName(config.ip);
String ip = inetAddress.getHostAddress();
// test reachable address :
try (Socket s = new Socket(ip, config.networkPort)) {
}
} catch (IOException | NumberFormatException ex) {
// no ip
throw new ModemConfigurationException(
config.ip + ":" + config.networkPort + " is not a reachable address:port", ex);
}
}
private String resolveEventualSymbolicLink(String serialPortOrIp) {
String keepResult = serialPortOrIp;
Path maybePath = Paths.get(serialPortOrIp);
File maybeFile = maybePath.toFile();
if (maybeFile.exists() && Files.isSymbolicLink(maybePath)) {
try {
maybePath = maybePath.toRealPath();
keepResult = maybePath.toAbsolutePath().toString();
} catch (IOException e) {
} // nothing to do, not a valid symbolic link, return
}
return keepResult;
}
public boolean isRunning() {
Modem finalModem = modem;
return finalModem != null
&& (finalModem.getStatus() == Status.Started || finalModem.getStatus() == Status.Starting);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
}
@Override
public void messageReceived(InboundMessage message) {
String sender = message.getOriginatorAddress().getAddress();
Payload payload = message.getPayload();
String messageText;
if (payload.getType().equals(Type.Text)) {
String text = payload.getText();
if (text != null) {
messageText = text;
} else {
logger.warn("Message has no payload !");
return;
}
} else {
byte[] bytes = payload.getBytes();
if (bytes != null) {
logger.warn("Message payload in binary format. Don't know how to handle it. Please report it.");
messageText = bytes.toString();
} else {
logger.warn("Message has no payload !");
return;
}
}
logger.debug("Receiving new message from {} : {}", sender, messageText);
// dispatch to conversation :
for (SMSConversationHandler child : getChildHandlers()) {
child.checkAndReceive(sender, messageText);
}
// channel trigger
String recipientAndMessage = sender + "|" + messageText;
triggerChannel(SMSModemBindingConstants.CHANNEL_TRIGGER_MODEM_RECEIVE, recipientAndMessage);
// prepare discovery service
senderMsisdn.add(sender);
final SMSConversationDiscoveryService finalDiscoveryService = discoveryService;
if (finalDiscoveryService != null) {
finalDiscoveryService.buildByAutoDiscovery(sender);
}
try { // delete message on the sim
Modem finalModem = modem;
if (finalModem != null) {
finalModem.delete(message);
}
} catch (CommunicationException e) {
logger.warn("Cannot delete message after receiving it !", e);
}
}
/**
* Send message
*
* @param recipient The recipient for the message
* @param text The message content
* @param deliveryReport If we should ask the network for a delivery report
*/
public void send(String recipient, String text, boolean deliveryReport, @Nullable String encoding) {
OutboundMessage out = new OutboundMessage(recipient, text);
try {
if (encoding != null && !encoding.isEmpty()) {
Encoding encoding2 = Encoding.valueOf(encoding);
out.setEncoding(encoding2);
}
} catch (IllegalArgumentException e) {
logger.warn("Encoding {} is not supported. Use Enc7, Enc8, EncUcs2, or EncCustom", encoding);
}
out.setRequestDeliveryReport(deliveryReport);
logger.debug("Sending message to {}", recipient);
Modem finalModem = modem;
if (finalModem != null) {
finalModem.queue(out);
}
}
/**
* Used by the scanning discovery service to create conversation
*
* @return All senders of the received messages since the last start
*/
public Set<String> getAllSender() {
return new HashSet<>(senderMsisdn);
}
@Override
public Collection<Class<? extends ThingHandlerService>> getServices() {
return Set.of(SMSModemActions.class, SMSConversationDiscoveryService.class);
}
@Override
public boolean processStatusCallback(Modem.Status oldStatus, Modem.Status newStatus) {
switch (newStatus) {
case Error:
String finalDescription = "unknown";
Modem finalModem = modem;
if (finalModem != null) {
finalDescription = finalModem.getDescription();
}
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"SMSLib reported an error on the underlying modem " + finalDescription);
break;
case Started:
updateStatus(ThingStatus.ONLINE);
break;
case Starting:
updateStatus(ThingStatus.UNKNOWN);
break;
case Stopped:
if (thing.getStatus() != ThingStatus.OFFLINE) {
updateStatus(ThingStatus.OFFLINE);
}
break;
case Stopping:
if (thing.getStatus() != ThingStatus.OFFLINE) {
updateStatus(ThingStatus.OFFLINE);
}
break;
}
return false;
}
public void setDiscoveryService(SMSConversationDiscoveryService smsConversationDiscoveryService) {
this.discoveryService = smsConversationDiscoveryService;
}
@Override
public void messageSent(OutboundMessage message) {
DeliveryStatus sentStatus;
switch (message.getSentStatus()) {
case Failed:
sentStatus = DeliveryStatus.FAILED;
break;
case Unsent:
case Queued:
sentStatus = DeliveryStatus.QUEUED;
break;
case Sent:
sentStatus = DeliveryStatus.SENT;
break;
default: // shoult not happened
sentStatus = DeliveryStatus.UNKNOWN;
break;
}
// dispatch to conversation :
MsIsdn recipientAddress = message.getRecipientAddress();
if (recipientAddress != null) {
String recipient = recipientAddress.getAddress();
for (SMSConversationHandler child : getChildHandlers()) {
child.checkAndUpdateDeliveryStatus(recipient, sentStatus);
}
}
}
@Override
public void messageDelivered(DeliveryReportMessage message) {
DeliveryStatus sentStatus;
switch (message.getDeliveryStatus()) {
case Delivered:
sentStatus = DeliveryStatus.DELIVERED;
break;
case Error:
case Failed:
sentStatus = DeliveryStatus.FAILED;
break;
case Expired:
sentStatus = DeliveryStatus.EXPIRED;
break;
case Pending:
sentStatus = DeliveryStatus.PENDING;
break;
case Unknown:
default:
sentStatus = DeliveryStatus.UNKNOWN;
break;
}
MsIsdn recipientAddress = message.getRecipientAddress();
if (recipientAddress != null) {
String recipient = recipientAddress.getAddress();
for (SMSConversationHandler child : getChildHandlers()) {
child.checkAndUpdateDeliveryStatus(recipient, sentStatus);
}
}
try {
Modem finalModem = modem;
if (finalModem != null) {
finalModem.delete(message);
}
} catch (CommunicationException e) {
logger.warn("Cannot delete delivery report after receiving it !", e);
}
}
private Set<SMSConversationHandler> getChildHandlers() {
return getThing().getThings().stream().map(Thing::getHandler).filter(Objects::nonNull)
.map(handler -> (SMSConversationHandler) handler).collect(Collectors.toSet());
}
@Override
public void setManufacturer(String manufacturer) {
thing.setProperty(SMSModemBindingConstants.PROPERTY_MANUFACTURER, manufacturer);
}
@Override
public void setModel(String model) {
thing.setProperty(SMSModemBindingConstants.PROPERTY_MODEL, model);
}
@Override
public void setSwVersion(String swVersion) {
thing.setProperty(SMSModemBindingConstants.PROPERTY_SWVERSION, swVersion);
}
@Override
public void setSerialNo(String serialNo) {
thing.setProperty(SMSModemBindingConstants.PROPERTY_SERIALNO, serialNo);
}
@Override
public void setImsi(String imsi) {
thing.setProperty(SMSModemBindingConstants.PROPERTY_IMSI, imsi);
}
@Override
public void setRssi(String rssi) {
thing.setProperty(SMSModemBindingConstants.PROPERTY_RSSI, rssi);
}
@Override
public void setMode(String mode) {
thing.setProperty(SMSModemBindingConstants.PROPERTY_MODE, mode);
}
@Override
public void setTotalSent(String totalSent) {
thing.setProperty(SMSModemBindingConstants.PROPERTY_TOTALSENT, totalSent);
}
@Override
public void setTotalFailed(String totalFailed) {
thing.setProperty(SMSModemBindingConstants.PROPERTY_TOTALFAILED, totalFailed);
}
@Override
public void setTotalReceived(String totalReceived) {
thing.setProperty(SMSModemBindingConstants.PROPERTY_TOTALRECEIVED, totalReceived);
}
@Override
public void setTotalFailures(String totalFailure) {
thing.setProperty(SMSModemBindingConstants.PROPERTY_TOTALFAILURE, totalFailure);
}
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="smsmodem" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
<name>SMSModem Binding</name>
<description>This binding handles a GSM modem connected to the openHAB server (Serial), or exposed on the network. It
can send and receive SMS.</description>
</binding:binding>

View File

@@ -0,0 +1,49 @@
# binding
binding.smsmodem.name = SMSModem Binding
binding.smsmodem.description = This binding handle a GSM modem connected to the openHAB server (Serial), or exposed on the network. It can send and receive SMS.
# thing types
thing-type.smsmodem.smsconversation.label = SMS Conversation
thing-type.smsmodem.smsconversation.description = Represents a conversation with a SMS recipient.
thing-type.smsmodem.smsmodembridge.label = SMSModem Bridge
thing-type.smsmodem.smsmodembridge.description = This bridge represents a serial modem.
thing-type.smsmodem.smsmodemremotebridge.label = SMSModem Remote Bridge
thing-type.smsmodem.smsmodemremotebridge.description = This bridge represents a modem exposed over the network.
# thing types config
thing-type.config.smsmodem.smsconversation.deliveryReport.label = Delivery Report
thing-type.config.smsmodem.smsconversation.deliveryReport.description = Ask network for delivery report.
thing-type.config.smsmodem.smsconversation.encoding.label = Encoding
thing-type.config.smsmodem.smsconversation.encoding.description = Encoding for the message to send. Default Enc7.
thing-type.config.smsmodem.smsconversation.recipient.label = Recipient Number
thing-type.config.smsmodem.smsconversation.recipient.description = The SMS number of the recipient.
thing-type.config.smsmodem.smsmodembridge.baud.label = Baud
thing-type.config.smsmodem.smsmodembridge.baud.description = Baud rate.
thing-type.config.smsmodem.smsmodembridge.delayBetweenSend.description = Delay between two messages (in milliseconds). Useful for slow modem.
thing-type.config.smsmodem.smsmodembridge.pollingInterval.description = Delay between polling for new messages (in seconds).
thing-type.config.smsmodem.smsmodembridge.serialPort.label = Serial Port
thing-type.config.smsmodem.smsmodembridge.serialPort.description = Serial port of the modem (usually /dev/ttyUSB0).
thing-type.config.smsmodem.smsmodembridge.simPin.label = Pin Code
thing-type.config.smsmodem.smsmodembridge.simPin.description = The pin (if set) for the sim card.
thing-type.config.smsmodem.smsmodemremotebridge.delayBetweenSend.description = Delay between two messages (in milliseconds). Useful for slow modem.
thing-type.config.smsmodem.smsmodemremotebridge.ip.label = Address
thing-type.config.smsmodem.smsmodemremotebridge.ip.description = IP address of the remote computer.
thing-type.config.smsmodem.smsmodemremotebridge.networkPort.label = Network Port
thing-type.config.smsmodem.smsmodemremotebridge.networkPort.description = Network port to join the remote service (a.k.a. ser2net).
thing-type.config.smsmodem.smsmodemremotebridge.pollingInterval.description = Delay between polling for new messages (in seconds).
thing-type.config.smsmodem.smsmodemremotebridge.simPin.label = Pin Code
thing-type.config.smsmodem.smsmodemremotebridge.simPin.description = The pin (if set) for the sim card.
# channel types
channel-type.smsmodem.deliverystatus.label = Delivery Status
channel-type.smsmodem.deliverystatus.description = Last message delivery status (either UNKNOWN, QUEUED, SENT, PENDING, DELIVERED, EXPIRED, or FAILED)
channel-type.smsmodem.receive.label = Message Received
channel-type.smsmodem.receive.description = Last message received
channel-type.smsmodem.send.label = Send Message
channel-type.smsmodem.send.description = Message to send to the recipient.
channel-type.smsmodem.smsmodemreceivetrigger.label = Message Received
channel-type.smsmodem.smsmodemreceivetrigger.description = Triggered when a message is received, in the form "<msisdn_sender>|<text>"

View File

@@ -0,0 +1,49 @@
# binding
binding.smsmodem.name = Extension SMSModem
binding.smsmodem.description = Cette extension gère un modem GSM supportant les messages AT et connecté en série, ou exposé sur le réseau. Elle peut envoyer et recevoir des SMS
# thing types
thing-type.smsmodem.smsconversation.label = Conversation SMS
thing-type.smsmodem.smsconversation.description = Représente une conversation avec un correspondant.
thing-type.smsmodem.smsmodembridge.label = SMS Modem
thing-type.smsmodem.smsmodembridge.description = Un modem connecté en série.
thing-type.smsmodem.smsmodemremotebridge.label = SMS Remote Modem
thing-type.smsmodem.smsmodemremotebridge.description = Un modem connecté par le réseau.
# thing types config
thing-type.config.smsmodem.smsconversation.deliveryReport.label = Accusé de réception
thing-type.config.smsmodem.smsconversation.deliveryReport.description = Demande au réseau un accusé de réception.
thing-type.config.smsmodem.smsconversation.encoding.label = Encodage
thing-type.config.smsmodem.smsconversation.encoding.description = Encodage du message à envoyer. Défaut Enc7.
thing-type.config.smsmodem.smsconversation.recipient.label = Numéro Du Correspondant
thing-type.config.smsmodem.smsconversation.recipient.description = Le numéro SMS du correspondant.
thing-type.config.smsmodem.smsmodembridge.baud.label = Taux (Baud)
thing-type.config.smsmodem.smsmodembridge.baud.description = Taux de transmission.
thing-type.config.smsmodem.smsmodembridge.delayBetweenSend.description = Délai entre deux envois (en millisecondes). Peut être utile pour les modems lents.
thing-type.config.smsmodem.smsmodembridge.pollingInterval.description = Délai entre deux essais de récupération de message (in seconds).
thing-type.config.smsmodem.smsmodembridge.serialPort.label = Port Série
thing-type.config.smsmodem.smsmodembridge.serialPort.description = Port série du modem (habituellement /dev/ttyUSB0).
thing-type.config.smsmodem.smsmodembridge.simPin.label = Code PIN
thing-type.config.smsmodem.smsmodembridge.simPin.description = Le code PIN (si nécessaire) de la carte SIM.
thing-type.config.smsmodem.smsmodemremotebridge.delayBetweenSend.description = Délai entre deux envois (en millisecondes). Peut être utile pour les modems lents.
thing-type.config.smsmodem.smsmodemremotebridge.ip.label = Addresse
thing-type.config.smsmodem.smsmodemremotebridge.ip.description = Addresse IP.
thing-type.config.smsmodem.smsmodemremotebridge.networkPort.label = Port Réseau
thing-type.config.smsmodem.smsmodemremotebridge.networkPort.description = Port réseau pour joindre le serveur (i.e. ser2net)
thing-type.config.smsmodem.smsmodemremotebridge.pollingInterval.description = Délai entre deux essais de récupération de message (in seconds).
thing-type.config.smsmodem.smsmodemremotebridge.simPin.label = Code PIN
thing-type.config.smsmodem.smsmodemremotebridge.simPin.description = Le code PIN (si nécessaire) de la carte SIM.
# channel types
channel-type.smsmodem.deliverystatus.label = Accusé De Réception
channel-type.smsmodem.deliverystatus.description = Dernier statut de message (soit UNKNOWN, QUEUED, SENT, PENDING, DELIVERED, EXPIRED, ou FAILED)
channel-type.smsmodem.receive.label = Message Reçu
channel-type.smsmodem.receive.description = Dernier message reçu
channel-type.smsmodem.send.label = Message Envoyé
channel-type.smsmodem.send.description = Message à envoyer au correspondant
channel-type.smsmodem.smsmodemreceivetrigger.label = Message Reçu
channel-type.smsmodem.smsmodemreceivetrigger.description = Déclenché quand un message est réceptionné, sous la forme "<msisdn_sender>|<text>"

View File

@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="smsmodem"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<thing-type id="smsconversation">
<supported-bridge-type-refs>
<bridge-type-ref id="smsmodembridge"/>
<bridge-type-ref id="smsmodemremotebridge"/>
</supported-bridge-type-refs>
<label>SMS Conversation</label>
<description>Represents a conversation with a SMS recipient.</description>
<channels>
<channel id="send" typeId="send"/>
<channel id="receive" typeId="receive"/>
<channel id="deliverystatus" typeId="deliverystatus"/>
</channels>
<representation-property>recipient</representation-property>
<config-description>
<parameter name="recipient" type="text" required="true">
<label>Recipient Number</label>
<description>The SMS number of the recipient.</description>
</parameter>
<parameter name="deliveryReport" type="boolean" required="false">
<label>Delivery Report</label>
<description>Ask network for delivery report.</description>
<default>false</default>
</parameter>
<parameter name="encoding" type="text" required="false">
<label>Encoding</label>
<options>
<option value="Enc7">Enc7</option>
<option value="Enc8">Enc8</option>
<option value="EncUcs2">EncUcs2</option>
<option value="EncCustom">EncCustom</option>
</options>
<description>Encoding for the message to send. Default Enc7</description>
<default>Enc7</default>
</parameter>
</config-description>
</thing-type>
<channel-type id="send">
<item-type>String</item-type>
<label>Send Message</label>
<description>Message to send to the recipient.</description>
</channel-type>
<channel-type id="receive">
<item-type>String</item-type>
<label>Message Received</label>
<description>Last message received</description>
</channel-type>
<channel-type id="deliverystatus">
<item-type>String</item-type>
<label>Delivery Status</label>
<description>Last message delivery status (either UNKNOWN, QUEUED, SENT, PENDING, DELIVERED, EXPIRED, or FAILED)</description>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,90 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="smsmodem"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<bridge-type id="smsmodembridge">
<label>SMSModem Bridge</label>
<description>This bridge represents a modem.</description>
<channels>
<channel id="receivetrigger" typeId="smsmodemreceivetrigger"/>
</channels>
<config-description>
<parameter name="serialPort" type="text" required="true">
<label>Serial Port</label>
<description>Serial port of the modem (usually /dev/ttyUSB0).</description>
<context>serial-port</context>
<default></default>
</parameter>
<parameter name="baud" type="integer" required="true">
<label>Baud</label>
<description>Baud rate.</description>
<default>19200</default>
</parameter>
<parameter name="simPin" type="text" required="false">
<label>Pin Code</label>
<description>The pin (if set) for the sim card.</description>
<default></default>
</parameter>
<parameter name="pollingInterval" type="integer">
<advanced>true</advanced>
<default>15</default>
<description>Delay between polling for new messages (in seconds).</description>
</parameter>
<parameter name="delayBetweenSend" type="integer">
<advanced>true</advanced>
<default>100</default>
<description>Delay between two messages (in milliseconds). Useful for slow modem.</description>
</parameter>
</config-description>
</bridge-type>
<bridge-type id="smsmodemremotebridge">
<label>SMSModem Remote Bridge</label>
<description>This bridge represents a modem on a network controlled computer.</description>
<channels>
<channel id="receivetrigger" typeId="smsmodemreceivetrigger"/>
</channels>
<config-description>
<parameter name="ip" type="text" required="true">
<label>IP Address</label>
<description>IP address of the remote computer.</description>
<default></default>
<context>network-address</context>
</parameter>
<parameter name="networkPort" type="integer" required="true">
<label>Network Port</label>
<description>Network port to join the remote service (a.k.a. ser2net).</description>
<default>2000</default>
</parameter>
<parameter name="simPin" type="text" required="false">
<label>Pin Code</label>
<description>The pin (if set) for the sim card.</description>
<default></default>
</parameter>
<parameter name="pollingInterval" type="integer">
<advanced>true</advanced>
<default>15</default>
<description>Delay between polling for new messages (in seconds).</description>
</parameter>
<parameter name="delayBetweenSend" type="integer">
<advanced>true</advanced>
<default>100</default>
<description>Delay between two messages (in milliseconds). Useful for slow modem.</description>
</parameter>
</config-description>
</bridge-type>
<channel-type id="smsmodemreceivetrigger">
<kind>trigger</kind>
<label>Message Received</label>
<description>Triggered when a message is received, in the form "&lt;msisdn_sender&gt;|&lt;text&gt;"</description>
<event/>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,22 @@
default.poll_reader=100
default.command_wait_unit=700
default.after_ip_connect_wait_unit=5000
default.wait_unit=200
default.char_wait_unit=10
default.timeout=30000
default.port_buffer=8192
default.delay_after_init1=10
default.delay_after_init2=10
default.delay_on_sim_error=5
default.delay_network_registration=10
default.delay_before_send_pdu=1
default.delay_after_pre_pin=1
default.delay_after_post_pin=1
default.cpin_without_ok=0
default.flowcontrol=IN
huawei.init1=AT+CFUN=1\r
huawei.init2=AT^CURC=0\r
huawei.memory_locations=SMSR
huawei_e3131.memory_locations=SM
wavecommodem.memory_locations=SMSR
wavecommodem.cpin_without_ok=1