Enable/Disable bluetooth (by shelling out to "blueutil power 1")

538 views
Skip to first unread message

Oliver Schrenk

unread,
Mar 21, 2015, 4:38:06 PM3/21/15
to hamme...@googlegroups.com
Hi,

I'm trying to enable/disable bluetooth based on my WiFi connection.

It seems that there is no official API to control bluetooth devices yet, so I wanted to use the command line tool https://github.com/toy/blueutil to control it. The tool works great from my terminal, so I thought I shell out to it.

I have some troubles running it from hammerspoon though

1. I don't find a a way to call command line from hammerspoon. Is there such a facility?
2. If I wrap it in an applescript call like so

```
ok,result = hs.applescript('do shell script "blueutil power 1"')
hs.alert.show(result)
```

as a result I get something which looks a pointer, as an example I get

```
table: 0x6180000265580
```

when I change the shell script to `ls /Users/` the result seems fine.



Do you have any pointers how I can achieve this?


Cheers,
Oliver

Chris Jones

unread,
Mar 21, 2015, 6:04:08 PM3/21/15
to Oliver Schrenk, hamme...@googlegroups.com
Hi

Hammerspoon doesn't currently offer its own API for executing system commands because Lua does - os.execute()

I'm not sure offhand why hs.applescript is returning a table, but you can dump the contents of a table with hs.inspect()

Cheers,
--
Chris Jones
--
You received this message because you are subscribed to the Google Groups "Hammerspoon" group.
To unsubscribe from this group and stop receiving emails from it, send an email to hammerspoon...@googlegroups.com.
To post to this group, send email to hamme...@googlegroups.com.
To view this discussion on the web, visit https://groups.google.com/d/msgid/hammerspoon/e71b8fba-d432-4530-a69c-fb8fdc049d3d%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Oliver Schrenk

unread,
Mar 22, 2015, 12:33:33 PM3/22/15
to hamme...@googlegroups.com, oliver....@gmail.com
I'm quite new to LUA, so sorry if these are beginner questions and ramblings. So it seems there are (at least) two mechanism to execute scripts.

`os.execute("ls /Users)` for when you are not really interested in the return value, or
[]

```
local handle = io.popen("ls /Users")
local result = handle:read("*a")
handle:close()
```

With the second alternative I I a nice result back. Both methods though fail to execute "blueutil power" command successfully. On the terminal it works just wonderful and returns either 0 or 1, depending on your bluetooth status.

The third alternative is to shell out using applescript and running it through hammerspoon. So you do

```
ok,result = hs.applescript('do shell script "blueutil power 1"')
print(hs.inspect(result))
```

Aha! Some useful information:

```
{
  NSAppleScriptErrorAppName = "Hammerspoon",
  NSAppleScriptErrorBriefMessage = "sh: blueutil: command not found",
  NSAppleScriptErrorMessage = "sh: blueutil: command not found",
  NSAppleScriptErrorNumber = 127,
  NSAppleScriptErrorRange = "NSRange: {0, 34}"
}
```

Of course. `blueutil` can't be found, because there is no $PATH. So this works now:

```
os.execute("/usr/local/bin/blueutil power 1")
```

Yeah. Some success! May it help the next soul.

asmagill

unread,
Mar 22, 2015, 6:03:39 PM3/22/15
to hamme...@googlegroups.com, oliver....@gmail.com
Just to put this out there, I have added the following to some of my personal modules:

--- hs._asm.extras.exec(command[, with_user_env]) -> output, status, type, rc
--- Function
--- Runs a shell command and returns stdout as a string (may include a trailing newline), followed by true or nil indicating if the command completed successfully, the exit type ("exit" or "signal"), and the result code.
---
---  If `with_user_env` is `true`, then invoke the user's default shell as an interactive login shell in which to execute the provided command in order to make sure their setup files are properly evaluated so extra path and environment variables can be set.  This is not done, if `with_user_env` is `false` or not provided, as it does add some overhead and is not always strictly necessary.
module.exec = function(command, user_env)
    local f
    if user_env then
        f = io.popen(os.getenv("SHELL").." -l -i -c \""..command.."\"", 'r')
    else
        f = io.popen(command, 'r')
    end
    local s = f:read('*a')
    local status, exit_type, rc = f:close()
    return s, status, exit_type, rc
end

This more closely resembles os.execute() because it returns status, exit_type, and rc (result code) like exec does, but also the output of the invocation... this:

result = module.exec("which ls") will return the string "/bin/ls" and store it in result, or
result, status, exit_type, rc = module.exec("which ls") returns "/bin/ls", true, exit, 0 and stores each in the corresponding variable.

As an added bonus, you could do module.exec("which blueutil", true) which causes this version to wrap the command with your shell and the appropriate args to invoke your login scripts, thus gaining environment variable changes like to PATH.  Eg:

> _asm.extras.exec("which blueutil")

nil exit 1


> _asm.extras.exec("which blueutil", true)

/usr/local/bin/blueutil

true exit 0



And I forget where it was asked, but applescript returns a table because at the time I ported it from Hydra, it either worked or it didn't and the results and/or error weren't always returned to Lua.  I mean to go back and clean up the return values so it's more lua friendly at some time, but haven't gotten around to it yet... someone else is more than welcome, as this isn't currently a high priority on my list since it works well enough to troubleshoot and use for basic applescripting.
Reply all
Reply to author
Forward
0 new messages