[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:
@@ -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>
|
||||
@@ -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";
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>"
|
||||
@@ -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>"
|
||||
@@ -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>
|
||||
@@ -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 "<msisdn_sender>|<text>"</description>
|
||||
<event/>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user