Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature - add generic command handling #194

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,35 @@ $ mqtt pub -t 'smartthings/Fireplace Lights/switch' -m 'off'
# Light goes off in SmartThings
```

A special command can also be sent (by using a different suffix e.g. set_state). The Bridge will subscribe to changes
in topics ending in set_state for all devices. Updates to these topics triggers a setStatus command on the device,
the device handler has to support this command:

```
command "setStatus"

...

def setStatus(type, status) {
log.trace("Setting status ${type}: ${status}")

sendEvent(name: type, value: status)
}
```

```
$ mqtt pub -t 'smartthings/Living Room Temperature/temperature/set_state' -m '72'
# Virtual temperature sensor is updated to reflect the new temperature
```

# Configuration

The bridge has one yaml file for configuration:

```
---
mqtt:
# Specify your MQTT Broker URL here
# Specify your MQTT Broker's hostname or IP address here
host: mqtt://localhost
# Example from CloudMQTT
# host: mqtt:///m10.cloudmqtt.com:19427
Expand All @@ -65,6 +86,7 @@ mqtt:
# state_write_suffix: set_state

# Suffix for the command topics $PREFACE/$DEVICE_NAME/$PROPERTY/$COMMAND_SUFFIX
# your physical device or application should write to this topic to execute commands in SmartThings devices that support them
# command_suffix: cmd

# Other optional settings from https://www.npmjs.com/package/mqtt#mqttclientstreambuilder-options
Expand Down
7 changes: 6 additions & 1 deletion _config.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
---
mqtt:
# Specify your MQTT Broker's hostname or IP address here
host: mqtt
host: mqtt://localhost

# Preface for the topics $PREFACE/$DEVICE_NAME/$PROPERTY
preface: smartthings

Expand All @@ -16,11 +17,15 @@ mqtt:
# state_write_suffix: set_state

# Suffix for the command topics $PREFACE/$DEVICE_NAME/$PROPERTY/$COMMAND_SUFFIX
# your physical device or application should write to this topic to execute commands in SmartThings devices that support them
# command_suffix: cmd

# Other optional settings from https://www.npmjs.com/package/mqtt#mqttclientstreambuilder-options
# username: AzureDiamond
# password: hunter2

# MQTT retains state changes be default, retain mode can be disabled:
# retain: false

# Port number to listen on
port: 8080
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "smartthings-mqtt-bridge",
"version": "3.0.0",
"version": "3.1.0",
"description": "Bridge between SmartThings and an MQTT broker",
"main": "server.js",
"bin": {
Expand Down
70 changes: 51 additions & 19 deletions smartapps/stj/mqtt-bridge.src/mqtt-bridge.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ import groovy.transform.Field
"acceleration"
]
],
"airQualitySensors": [
name: "AirQuality Sensor",
capability: "capability.airQualitySensor",
attributes: [
"airQuality"
]
],
"airQualitySensors": [
name: "AirQuality Sensor",
capability: "capability.airQualitySensor",
attributes: [
"airQuality"
]
],
"alarm": [
name: "Alarm",
capability: "capability.alarm",
Expand Down Expand Up @@ -120,14 +120,14 @@ import groovy.transform.Field
],
action: "actionOpenClosed"
],
"dustSensors": [
name: "Dust Sensor",
capability: "capability.dustSensor",
attributes: [
"fineDustLevel",
"dustLevel"
]
],
"dustSensors": [
name: "Dust Sensor",
capability: "capability.dustSensor",
attributes: [
"fineDustLevel",
"dustLevel"
]
],
"energyMeter": [
name: "Energy Meter",
capability: "capability.energyMeter",
Expand Down Expand Up @@ -228,7 +228,8 @@ import groovy.transform.Field
capability: "capability.relativeHumidityMeasurement",
attributes: [
"humidity"
]
],
action: "actionHumiditySensors"
],
"relaySwitch": [
name: "Relay Switch",
Expand Down Expand Up @@ -316,7 +317,8 @@ import groovy.transform.Field
capability: "capability.temperatureMeasurement",
attributes: [
"temperature"
]
],
action: "actionTemperatureSensors"
],
"thermostat": [
name: "Thermostat",
Expand Down Expand Up @@ -560,13 +562,23 @@ def bridgeHandler(evt) {
device.setStatus(json.type, json.value)
state.ignoreEvent = json;
}
else {
log.debug "Device doesn't support setStatus command."
}
}
else {
if (capability.containsKey("action")) {
def action = capability["action"]
// Yes, this is calling the method dynamically
"$action"(device, json.type, json.value)
}
else if (device.getSupportedCommands().any {it.name == json.type}) {
log.debug "Calling device command ${json.type} with ${json.value}"
device."$json.type"(json.value)
}
else {
log.debug "Device doesn't support ${json.type} command."
}
}
}
}
Expand Down Expand Up @@ -705,16 +717,36 @@ def actionColorTemperature(device, attribute, value) {
device.setColorTemperature(value as int)
}

//Temperature Sensors don't have commands but a simulated sensor might hence the hasCommand() check.
def actionTemperatureSensors(device, attribute, value) {
if (device.hasCommand("temperature")) {
device.temperature(value as int)
}
if (device.hasCommand("setTemperature")) {
device.setTemperature(value as int)
}
}

//Humidity Sensors don't have commands but a simulated sensor might hence the hasCommand() check.
def actionHumiditySensors(device, attribute, value) {
if (device.hasCommand("humidity")) {
device.humidity(value as int)
}
if (device.hasCommand("setHumidity")) {
device.setHumidity(value as int)
}
}

def actionLevel(device, attribute, value) {
device.setLevel(value as int)
}

def actionPresence(device, attribute, value) {
if (value == "present") {
device.arrived();
device.arrived();
}
else if (value == "not present") {
device.departed();
device.departed();
}
}

Expand Down