Skip to content

Commit 0491c09

Browse files
committed
Merge branch 'master' of github.com:pimatic/pimatic-shell-execute
2 parents 1abf15d + 517e4f7 commit 0491c09

4 files changed

+97
-6
lines changed

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,28 @@ If you're running pimatic on a RaspberryPi, you can use the following sensors fo
107107
"interval": 60000
108108
}
109109

110+
111+
### ShellButtons Device
112+
113+
You can define a button device with buttons that trigger individual shell commands, eliminating the need for individual rules:
114+
115+
{
116+
"id": "tv-remote",
117+
"name": "TV Remote",
118+
"class": "ShellButtons",
119+
"buttons": [
120+
{
121+
"id": "tv-power",
122+
"text": "PWR",
123+
"onPress": "irsend SEND_ONCE tvset KEY_POWER",
124+
"confirm": true
125+
}
126+
]
127+
}
128+
129+
The given example shows the possibility to create an infrared remote in the pimatic frontend using lirc.
130+
The `onPress` command can be any bash command or file you may want to execute.
131+
110132
### ShellPresenceSensor Device
111133

112134
You can define a presence sensor whose state gets updated with the output of shell command. In some

device-config-schema.coffee

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,36 @@ module.exports = {
3333
type: "boolean"
3434
default: false
3535
}
36+
ShellButtons: {
37+
title: "ShellButtons config options"
38+
type: "object"
39+
extensions: ["xLink"]
40+
properties:
41+
buttons:
42+
description: "Buttons and their actions once they are pressed"
43+
type: "array"
44+
default: []
45+
format: "table"
46+
items:
47+
type: "object"
48+
properties:
49+
id:
50+
description: "ID for the button"
51+
type: "string"
52+
text:
53+
description: "Label for the button"
54+
type: "string"
55+
onPress:
56+
description: "
57+
Shell command to be executed, when the button is
58+
pressed
59+
"
60+
type: "string"
61+
confirm:
62+
description: "Ask the user to confirm the button press"
63+
type: "boolean"
64+
default: false
65+
}
3666
ShellSensor: {
3767
title: "ShellSensor config options"
3868
type: "object"
@@ -96,7 +126,10 @@ module.exports = {
96126
type: "boolean"
97127
default: false
98128
resetTime:
99-
description: "Time in milliseconds after that the presence value is reset to absent."
129+
description: "
130+
Time in milliseconds after that the presence value is
131+
reset to absent.
132+
"
100133
type: "integer"
101134
default: 10000
102135
}

shell-execute-config-schema.coffee

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@ module.exports = {
44
properties:
55
sequential:
66
description: "
7-
Run all shell commands sequential (not in parallel). Enable this if you have commands
8-
that should not be execute in parallel
7+
Run all shell commands sequential (not in parallel). Enable
8+
this if you have commands that should not be execute in parallel
99
"
1010
type: "boolean"
1111
default: false
1212
shell:
13-
description: "Shell to execute a command with. Default: '/bin/sh' on UNIX, 'cmd.exe' on Windows"
13+
description: "
14+
Shell to execute a command with. Default:
15+
'/bin/sh' on UNIX, 'cmd.exe' on Windows
16+
"
1417
type: "string"
1518
required: false
1619
cwd:

shell-execute.coffee

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ module.exports = (env) ->
1616
)
1717
settled = (promise) -> Promise.settle([promise])
1818

19-
transformError = (error) =>
19+
transformError = (error) ->
2020
if error.code? and error.cause?
2121
cause = String(error.cause).replace(/(\r\n|\n|\r)/gm," ").trim()
2222
error = new Error "Command execution failed with exit code #{error.code} (#{cause})"
@@ -35,6 +35,12 @@ module.exports = (env) ->
3535
createCallback: (config, lastState) => return new ShellSwitch(config, lastState)
3636
})
3737

38+
@framework.deviceManager.registerDeviceClass("ShellButtons", {
39+
configDef: deviceConfigDef.ShellButtons,
40+
createCallback: (config, lastState) ->
41+
return new ShellButtons(config, lastState)
42+
})
43+
3844
@framework.deviceManager.registerDeviceClass("ShellSensor", {
3945
configDef: deviceConfigDef.ShellSensor,
4046
createCallback: (config, lastState) => return new ShellSensor(config, lastState)
@@ -120,7 +126,34 @@ module.exports = (env) ->
120126
).catch( (error) =>
121127
@base.rejectWithErrorString Promise.reject, transformError(error)
122128
)
123-
129+
130+
class ShellButtons extends env.devices.ButtonsDevice
131+
132+
constructor: (@config, lastState) ->
133+
@name = @config.name
134+
@id = @config.id
135+
@base = commons.base @, @config.class
136+
137+
# pass config to parent constructor
138+
super(@config)
139+
140+
destroy: () ->
141+
super()
142+
143+
getButton: -> Promise.resolve(@_lastPressedButton)
144+
145+
buttonPressed: (buttonId) ->
146+
for b in @config.buttons
147+
if b.id is buttonId
148+
command = b.onPress
149+
return exec(command, plugin.execOptions).then( ({stdout, stderr}) =>
150+
@base.error "stderr output from on/offCommand for
151+
#{@name}: #{stderr}" if stderr.length isnt 0
152+
).catch( (error) =>
153+
@base.rejectWithErrorString Promise.reject, transformError(error)
154+
)
155+
throw new Error("No button with the id #{buttonId} found")
156+
124157
class ShellSensor extends env.devices.Sensor
125158

126159
constructor: (@config, lastState) ->

0 commit comments

Comments
 (0)