Skip to content

Commit

Permalink
[smsmodem] Split local and remote modem in two thing-types
Browse files Browse the repository at this point in the history
Signed-off-by: Gwendal Roulleau <[email protected]>
  • Loading branch information
dalgwen committed Aug 22, 2022
1 parent 30482c7 commit 279dc21
Show file tree
Hide file tree
Showing 10 changed files with 185 additions and 62 deletions.
34 changes: 22 additions & 12 deletions bundles/org.openhab.binding.smsmodem/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,33 @@ The following devices have been reported functional :

Two things are supported by this binding :

- A *smsmodembridge*, representing the dongle
- A *smsmodembridge*, representing the dongle connected on the local computer
- A *smsmodemremotebridge*, representing the dongle exposed over the network (with ser2net or other similar software)
- A *smsconversation*, representing a conversation between one distant msisdn and the msisdn on the sim card in the dongle.

## Discovery

There is no discovery process for *smsmodembridge* thing.
There is no discovery process for *smsmodembridge* or *smsmodemremotebridge* thing.
A *smsconversation* thing will be discovered and added to the inbox everytime the modem should receive a SMS by a new sender.

## Thing Configuration

The *smsmodembridge* thing requires at least two parameters to work properly (serialPortOrIP, baudOrNetworkPort).
Depending on the nature of the connection (direct serial modem, or serial over network), this two fields will be used differently :
The *smsmodembridge* or *smsmodemremotebridge* things requires at least two parameters to work properly.

For local *smsmodembridge*:

| Parameter Name | type | direct serial modem |
|----------------|-------|----------------------|
|serialPort| text | The serial port to access (eg. /dev/tty/USBx) |
|baud| integer | Baud rate |

For remote *smsmodemremotebridge*:

| Parameter Name | type | serial over network |
|----------------|-------|----------------------|
|ip| text | IP address of the computer hosting the ser2net service|
|networkPort| integer | The network port of the ser2net service |

| Parameter Name | type | direct serial modem | serial over network |
|----------------|-------|----------------------|----------------------|
|serialPortOrIP| text | The serial port to access (eg. /dev/tty/USBx) | IP address of the computer hosting the ser2net service|
|baudOrNetworkPort| integer | Baud rate | The network port of the ser2net service |

The other parameters are optional :

Expand Down Expand Up @@ -61,7 +71,7 @@ The *smsconversation* supports the following channels :

## Trigger channels

The *smsmodembridge* has the following trigger channel :
The *smsmodembridge* and *smsmodemremotebridge* has the following trigger channel :
| Channel ID | event |
|---------------------|----------------------------|
|receivetrigger| The msisdn and message received (concatened with the '\|' character as a separator)|
Expand All @@ -81,7 +91,7 @@ val smsAction = getActions("smsmodem","smsmodem:smsmodembridge:<uid>")
var smsAction = actions.get("smsmodem","smsmodem:smsmodembridge:<uid>");
```

Where uid is the Bridge UID of the *smsconversation* thing.
Where uid is the Bridge UID of the *smsmodembridge* thing.

Once this action instance is retrieved, you can invoke the 'send' method on it:

Expand All @@ -102,7 +112,7 @@ smsAction.sendSMS("1234567890", "Hello world!", "EncUcs2")
things/smsmodem.things:

```
Bridge smsmodem:smsmodembridge:adonglename "USB 3G Dongle " [ serialPortOrIP="/dev/ttyUSB0", baudOrNetworkPort="19200", enableAutoDiscovery="true" ] {
Bridge smsmodem:smsmodembridge:adonglename "USB 3G Dongle " [ serialPort="/dev/ttyUSB0", baud="19200" ] {
Thing smsconversation aconversationname [ recipient="XXXXXXXXXXX", deliveryReport="true" ]
}
```
Expand Down Expand Up @@ -132,5 +142,5 @@ def smscommand(event):
sender_and_message = event.event.split("|")
sender = sender_and_message[0]
content = sender_and_message[1]
actions.get("smsmodem", "smsmodem:smsmodembridge:dongleuid").send("336123456789", sender + "send the following message:" + content)
actions.get("smsmodem", "smsmodem:smsmodembridge:dongleuid").send("336123456789", sender + " just send the following message: " + content)
```
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,17 @@ public class SMSModemBindingConstants {
// 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";

// List of all Parameters
public static final String BRIDGE_PARAMETER_SERIALPORTORIP = "serialPortOrIP";
public static final String BRIDGE_PARAMETER_BAUDRATEORPORT = "baudOrNetworkPort";
public static final String BRIDGE_PARAMETER_SIMPIN = "simPin";

// parameter
public static final String SMSCONVERSATION_PARAMETER_RECIPIENT = "recipient";
public static final String SMSCONVERSATION_ASK_DELIVERY_REPORT = "deliveryReport";

// List of all properties
public static final String PROPERTY_MANUFACTURER = Thing.PROPERTY_VENDOR;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
@NonNullByDefault
public class SMSModemBridgeConfiguration {

public String serialPortOrIP = "";
public Integer baudOrNetworkPort = 9800;
public String serialPort = "";
public Integer baud = 9800;
public String simPin = "";
public Integer pollingInterval = 15;
public Integer delayBetweenSend = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/
package org.openhab.binding.smsmodem.internal;

import java.util.HashSet;
import java.util.Set;

import org.eclipse.jdt.annotation.NonNullByDefault;
Expand Down Expand Up @@ -40,8 +41,11 @@
@NonNullByDefault
public class SMSModemHandlerFactory extends BaseThingHandlerFactory {

public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set
.of(SMSModemBridgeHandler.SUPPORTED_THING_TYPES_UIDS, SMSConversationHandler.SUPPORTED_THING_TYPES_UIDS);
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;

Expand All @@ -63,7 +67,7 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) {
protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();

if (SMSModemBridgeHandler.SUPPORTED_THING_TYPES_UIDS.equals(thingTypeUID)) {
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);
Expand All @@ -75,7 +79,7 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) {
@Override
public @Nullable Thing createThing(ThingTypeUID thingTypeUID, Configuration configuration,
@Nullable ThingUID thingUID, @Nullable ThingUID bridgeUID) {
if (SMSModemBridgeHandler.SUPPORTED_THING_TYPES_UIDS.equals(thingTypeUID)) {
if (SMSModemBridgeHandler.SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID)) {
return super.createThing(thingTypeUID, configuration, thingUID, null);
}
if (SMSConversationHandler.SUPPORTED_THING_TYPES_UIDS.equals(thingTypeUID)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
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;
Expand Down Expand Up @@ -70,7 +71,9 @@
public class SMSModemBridgeHandler extends BaseBridgeHandler
implements IModemStatusListener, IInboundOutboundMessageListener, IDeviceInformationListener {

public static final ThingTypeUID SUPPORTED_THING_TYPES_UIDS = SMSModemBindingConstants.SMSMODEMBRIDGE_THING_TYPE;
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);

Expand Down Expand Up @@ -133,21 +136,34 @@ private void checkAndStartModemIfNeeded() {
if (shouldRun && !isRunning()) {
logger.debug("Initializing smsmodem");
// ensure the underlying modem is stopped before trying to (re)starting it :
SMSModemBridgeConfiguration config = getConfigAs(SMSModemBridgeConfiguration.class);
if (modem != null) {
modem.stop();
} else {
modem = new Modem(serialPortManager, resolveEventualSymbolicLink(config.serialPortOrIP),
Integer.valueOf(config.baudOrNetworkPort), config.simPin, scheduler, config.pollingInterval,
}
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");
}
checkParam(config);
logger.debug("Now trying to start SMSModem {}/{}", config.serialPortOrIP, config.baudOrNetworkPort);
logger.debug("Now trying to start SMSModem {}", logName);
modem.registerStatusListener(this);
modem.registerMessageListener(this);
modem.registerInformationListener(this);
modem.start();
logger.debug("SMSModem {}/{} started", config.serialPortOrIP, config.baudOrNetworkPort);
logger.debug("SMSModem {} started", logName);
}
} catch (ModemConfigurationException e) {
String message = e.getMessage();
Expand All @@ -157,22 +173,28 @@ private void checkAndStartModemIfNeeded() {
}

private void checkParam(SMSModemBridgeConfiguration config) throws ModemConfigurationException {
String realSerialPortOrIP = resolveEventualSymbolicLink(config.serialPortOrIP);
SerialPortIdentifier identifier = serialPortManager.getIdentifier(realSerialPortOrIP);
String realSerialPort = resolveEventualSymbolicLink(config.serialPort);
SerialPortIdentifier identifier = serialPortManager.getIdentifier(realSerialPort);
if (identifier == null) {
try {
InetAddress inetAddress = InetAddress.getByName(realSerialPortOrIP);
realSerialPortOrIP = inetAddress.getHostAddress();
// no serial port
throw new ModemConfigurationException(
realSerialPort + " with " + config.baud + " is not a valid serial port | baud");
}
}

// test reachable address :
try (Socket s = new Socket(realSerialPortOrIP, config.baudOrNetworkPort)) {
}
private void checkRemoteParam(SMSModemRemoteBridgeConfiguration config) throws ModemConfigurationException {
try {
InetAddress inetAddress = InetAddress.getByName(config.ip);
String ip = inetAddress.getHostAddress();

} catch (IOException | NumberFormatException ex) {
// no serial port and no ip
throw new ModemConfigurationException(realSerialPortOrIP + " with " + config.baudOrNetworkPort
+ " is not a serial port/baud or a reachable address/port", ex);
// 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);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ binding.smsmodem.description = This binding handle a GSM modem connected to the
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 modem.
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

Expand All @@ -18,14 +20,22 @@ 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.baudOrNetworkPort.label = Baud Or Network Port
thing-type.config.smsmodem.smsmodembridge.baudOrNetworkPort.description = Baud rate, in case of a serial modem, or network port if it is on another machine.
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.serialPortOrIP.label = Address
thing-type.config.smsmodem.smsmodembridge.serialPortOrIP.description = Serial port of the modem, or the IP address if it is a network one.
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

Expand Down
Loading

0 comments on commit 279dc21

Please sign in to comment.