I’m trying to make an “Airplane-Mode” script for macOS.
This script works and turns Wi-Fi & Bluetooth on and off.
-- Don't click [Open this Scriplet in your Editor:]
tell application "System Events" to tell process "SystemUIServer"
-- Wi-Fi
set wifi to (first menu bar item whose value of attribute "AXDescription" contains "Wi-Fi") of menu bar 1
click wifi
tell (first menu item whose title is "Turn Wi-Fi Off") of menu of wifi
click
click menu item "Turn Wi-Fi Off"
tell (first menu item whose title is "Turn Wi-Fi On") of menu of wifi
click
click menu item "Turn Wi-Fi On"
end tell
end tell
-- Bluetooth
set bt to (first menu bar item whose value of attribute "AXDescription" contains "bluetooth") of menu bar 1
click bt
tell (first menu item whose title is "Turn Bluetooth Off") of menu of bt
click
click menu item "Turn Bluetooth Off"
tell (first menu item whose title is "Turn Bluetooth On") of menu of bt
click
click menu item "Turn Bluetooth On"
end tell
end tell
end tell
The problem is (for example) when Wi-Fi is ON & Bluetooth Off the script turns Wi-Fi Off and turns Bluetooth ON.
But I want that Wi-Fi & Bluetooth turn Off at the same time (and On at the same time) like the Airplane-Mode (iOS, Android).
I tried to use if/else but I don’t get it so I guess I need a little bit help
This sets state of Bluetooth to the state of Wi_fi:
tell application "System Events" to tell process "SystemUIServer"
-- Wi-Fi old state
try
set wifi to (first menu bar item whose value of attribute "AXDescription" contains "not enabled") of menu bar 1
set wifi_IsOn to false
on error
set wifi to (first menu bar item whose value of attribute "AXDescription" contains "Wi-Fi") of menu bar 1
set wifi_IsOn to true
end try
-- click Wi-Fi menu item
tell wifi
click it
if wifi_IsOn then
click menu item "Turn Wi-Fi Off" of menu 1
set bluetoothDescription to "Turn Bluetooth Off"
else
click menu item "Turn Wi-Fi On" of menu 1
set bluetoothDescription to "Turn Bluetooth On"
end if
end tell
-- Bluetooth
set bt to (first menu bar item whose value of attribute "AXDescription" contains "bluetooth") of menu bar 1
click bt
click (first menu item whose title is bluetoothDescription) of menu 1 of bt
end tell
NOTE: It makes sense to use completely different approach . If the OP is intеrested, I can wrote script for this workaround (no need GUI scripting, uses AsObjC):
script gets Bluetooth current state
script then turns Wi-Fi on/off according to Bluetooth current state
all code should be putted into the on idle handler
I wrote it. Save this script as stay-open application, then run it:
-- Set Wi_Fi on/off according to Bluetooth state
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "IOBluetooth"
use framework "CoreWLAN"
use scripting additions
property CWInterface : a reference to current application's CWInterface
property IOBluetoothHostController : a reference to current application's IOBluetoothHostController
on idle -- comment to debug
-- get Bluetooth current state
set controller to IOBluetoothHostController's alloc()'s init()
set Bluetooth_isOn to (controller's powerState()) as boolean
-- turn Wi_Fi state according to Bluetooth current state
if Bluetooth_isOn then
powerControlEveryWiFiDevices(true) of me
else
powerControlEveryWiFiDevices(false) of me
end if
return 1
end idle -- comment to debug
on powerControlEveryWiFiDevices(aFlag as boolean)
set allNames to CWInterface's interfaceNames()'s allObjects() as list
if allNames = {} then return false
set powerList to {}
repeat with i in allNames
set j to contents of i
set aInterface to (CWInterface's interfaceWithName:j)
set wRes to (aInterface's setPower:aFlag |error|:(missing value))
-- Get Power state and check it
set aPower to (aInterface's powerOn()) as boolean
if aPower = (not aFlag) then
if aFlag = true then
set aStat to " on "
else
set aStat to " off "
end if
display notification "Error occured in power" & aStat & "an Wifi deviece ( " & j & " )...."
end if
set the end of powerList to aPower
end repeat
return ({aFlag} is in powerList)
end powerControlEveryWiFiDevices
Your first script works fine! I changed some parts (macOS in German) and created a shortcut with Automator (service) to run it system-wide.
macOS in German:
tell application "System Events" to tell process "SystemUIServer"
-- Wi-Fi old state
try
set wifi to (first menu bar item whose value of attribute "AXDescription" contains "nicht aktiviert") of menu bar 1
set wifi_IsOn to false
on error
set wifi to (first menu bar item whose value of attribute "AXDescription" contains "WLAN") of menu bar 1
set wifi_IsOn to true
end try
-- click Wi-Fi menu item
tell wifi
click it
if wifi_IsOn then
click menu item "WLAN deaktivieren" of menu 1
set bluetoothDescription to "Bluetooth deaktivieren"
else
click menu item "WLAN aktivieren" of menu 1
set bluetoothDescription to "Bluetooth aktivieren"
end if
end tell
-- Bluetooth
set bt to (first menu bar item whose value of attribute "AXDescription" contains "bluetooth") of menu bar 1
click bt
click (first menu item whose title is bluetoothDescription) of menu of bt
end tell
It works well under macOS Catalina but unfortunately it doesn’t under Big Sur (new control center)
Your second script just works if I turn on/off bluetooth manually and it changes wi-fi (on/off), as well…
I’m trying to figure out how to change your first script so that it works under Catalina & Big Sur. But I don’t get it together
I haven’t switched to Big Sur yet, so I can’t help with its GUI scripting. But here’s a version of my first script that uses as little GUI scripting as possible - only the Bluetooth part. It will be easier to tweak for Big Sur:
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "CoreWLAN"
use scripting additions
property CWInterface : a reference to current application's CWInterface
-- Wi_Fi part. No need GUI scripting
if (do shell script "networksetup -getinfo Wi-Fi | grep Router") begins with "IPv6 Router: none" then
powerControlEveryWiFiDevices(true) of me -- set WiFi on
set bluetoothDescription to "Turn Bluetooth On"
else
powerControlEveryWiFiDevices(false) of me -- set WiFi off
set bluetoothDescription to "Turn Bluetooth Off"
end if
-- Bluetooth part. Uses GUI scripting.
tell application "System Events" to tell process "SystemUIServer" to tell menu bar 1
tell (first menu bar item whose value of attribute "AXDescription" contains "bluetooth")
click it
click (first menu item whose title is bluetoothDescription) of menu 1
end tell
end tell
-- Wi_Fi handler. No need GUI scripting
on powerControlEveryWiFiDevices(aFlag as boolean)
set allNames to CWInterface's interfaceNames()'s allObjects() as list
if allNames = {} then return false
set powerList to {}
repeat with i in allNames
set j to contents of i
set aInterface to (CWInterface's interfaceWithName:j)
set wRes to (aInterface's setPower:aFlag |error|:(missing value))
-- Get Power state and check it
set aPower to (aInterface's powerOn()) as boolean
if aPower = (not aFlag) then
if aFlag = true then
set aStat to " on "
else
set aStat to " off "
end if
display notification "Error occured in power" & aStat & "an Wifi deviece ( " & j & " )...."
end if
set the end of powerList to aPower
end repeat
return ({aFlag} is in powerList)
end powerControlEveryWiFiDevices
set status_wifi to do shell script "networksetup -getairportpower en0" -- get WiFi-status (Off or On)
set status_bt to do shell script "/usr/local/bin/blueutil --power" -- get Bluetooth-status (0 or 1)*
if status_wifi ends with "On" or status_bt ends with "1" then
do shell script "networksetup -setairportpower en1 off" -- set WiFi off
do shell script "/usr/local/bin/blueutil --power 0" -- set Bluetooth off*
else
do shell script "networksetup -setairportpower en1 on" -- set WiFi on
do shell script "/usr/local/bin/blueutil --power 1" -- set Bluetooth off*
end if
(*
* you need to download blueutil (https://github.com/toy/blueutil)
and install it with Homebrew (https://brew.sh)
then you can run it in Terminal (or as "do shell script" in AppleScript)
*)
Unfortunately I didn’t find a way to use a terminal command for Bluetooth…
Therefore I installed Blueutil so that there is no need (for me) to use GUI scripting.
The script works in Catalina & Big Sur if Blueutil (https://github.com/toy/blueutil) is installed on your Mac.
Maybe it’s not the most elegant way but it works for me.
Thx
Of course, this is a matter of taste, but I find the method using SystemUIServer more elegant than opening the System Preferences window or installing a third-party utility. In any case, a wide choice of the 3 methods proposed here will not hurt anyone.