revned / proximity Goto Github PK
View Code? Open in Web Editor NEWBluetooth device proximity detection.
Bluetooth device proximity detection.
Hi there, would love to checkout how proximity works, however, I cannot seem to select a blue-tooth device. In the bluetooth section of the preferences I have a message "A bluetooth-enabled device has not be selected". Clicking "Change Device" does not do anything.
Am I missing something? My Galaxy S5 is connected to my mac and works with other bluetooth proximity software.
Thanks much for any help!
My mac:
Model Name: iMac
Model Identifier: iMac14,2
Processor Name: Intel Core i5
Processor Speed: 3.2 GHz
Number of Processors: 1
Total Number of Cores: 4
L2 Cache (per Core): 256 KB
L3 Cache: 6 MB
Memory: 16 GB
Boot ROM Version: IM142.0118.B07
SMC Version (system): 2.15f7
I would suggest that you implemented a way to control when scripts trickered based on the strength of the bluetooth connection. This would be greatly appreciated.
The UI presents editable text fields that point to script file names. Users can enter .applescript files, .sh files, or other scripts. However, Proximity only runs compiled .scpt files: all others are silently ignored.
Please amend the UI to prevent such confusion.
Finally, consider adding support for other script types, and adding the file extensions to the Finder script selector.
I click on it and nothing happens. IS there a known incompatibility with Yosemite?
Please include a README.md file that describes Proximity's purpose, and links to download the app.
Please tell us the state of the project.
My background: I change the job and in the new company you need to pay pizza for the whole team if you forget to lock your screen :-)
See https://apple.stackexchange.com/questions/376729/automatically-lock-screen-if-i-leave-the-macbook
I would like to automate this screen-lock.
I know myself. I love to work, that's why I have little focus/energy on tasks like locking the screen.
I am running Lion DP4 and just downloaded Proximity.
The application will open, however, if I try and open up Preferences.... nothing happens.
The original icons didn't fall into my taste, so I made my own. You can find them here http://my.pogoplug.com/share/p-HDewVMlFLuwy5xpVvmZw/
Btw the web interface doesn't like the transparent pngs, so you will have to download them to view them.
Hope you like them.
As Google Code will be dead on 25 Jan, would you mind to move the 1.5 release files to somewhere else? (eq. GitHub releases)
(Refs Homebrew/homebrew-cask#17075)
Sometimes BT devices need some time to wake up and will not respond to the
fist query. I had to patch Proximity (even previous versions) like below to
make out of range detection more reliable.
Index: reduxcomputing-proximity-read-only/AppController.m =================================================================== --- reduxcomputing-proximity-read-only/AppController.m (revision 22) +++ reduxcomputing-proximity-read-only/AppController.m (working copy) @@ -1,6 +1,6 @@ #import "AppController.h" +#include - @implementation AppController @@ -91,9 +91,12 @@ - (BOOL)isInRange { - if( device && [device remoteNameRequest:nil] == kIOReturnSuccess ) - return true; - + int repeat_count = 3; + do { + if( device && [device remoteNameRequest:nil] == kIOReturnSuccess ) + return true; + usleep(500000L); + } while(--repeat_count); return false; }
Hey guys,
I've been trying to make this work under Mountain Lion. All seems OK expect one problem. Basically when you click the statusbar icon, the program hangs there for 4-5 seconds. I've identified the culprit but can't seem to find a valid replacement :
in userdefaultsload function :
device = [NSKeyedUnarchiver unarchiveObjectWithData:deviceAsData];
Also, I've modified the script a bit the work better with 10.8 :
Thanks a lot for your help
Cheers
Here's the full AppController.m
#import "AppController.h"
@implementation AppController
#pragma mark -
#pragma mark Delegate Methods
- (void)applicationWillTerminate:(NSNotification *)aNotification
{
[self stopMonitoring];
}
- (void)awakeFromNib
{
NSBundle *bundle = [NSBundle mainBundle];
inRangeImage = [[NSImage alloc] initWithContentsOfFile: [bundle pathForResource: @"inRange" ofType: @"png"]];
inRangeAltImage = [[NSImage alloc] initWithContentsOfFile: [bundle pathForResource: @"inRangeAlt" ofType: @"png"]];
outOfRangeImage = [[NSImage alloc] initWithContentsOfFile: [bundle pathForResource: @"outRange" ofType: @"png"]];
outOfRangeAltImage = [[NSImage alloc] initWithContentsOfFile: [bundle pathForResource: @"outOfRange" ofType: @"png"]];
priorStatus = OutOfRange;
[self createMenuBar];
[self userDefaultsLoad];
}
- (void)windowWillClose:(NSNotification *)aNotification
{
[self userDefaultsSave];
[self stopMonitoring];
[self startMonitoring];
}
#pragma mark -
#pragma mark AppController Methods
- (void)createMenuBar
{
NSMenu *myMenu;
NSMenuItem *menuItem;
// Menu for status bar item
myMenu = [[NSMenu alloc] init];
// Prefences menu item
menuItem = [myMenu addItemWithTitle:@"Preferences" action:@selector(showWindow:) keyEquivalent:@""];
[menuItem setTarget:self];
// Quit menu item
[myMenu addItemWithTitle:@"Quit" action:@selector(terminate:) keyEquivalent:@""];
// Space on status bar
statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
// Attributes of space on status bar
[statusItem setHighlightMode:YES];
[statusItem setMenu:myMenu];
[self menuIconOutOfRange];
}
- (void)handleTimer:(NSTimer *)theTimer
{
if( [self isInRange] )
{
if( priorStatus == OutOfRange )
{
priorStatus = InRange;
[self menuIconInRange];
[self runInRangeScript];
}
}
else
{
if( priorStatus == InRange )
{
priorStatus = OutOfRange;
[self menuIconOutOfRange];
[self runOutOfRangeScript];
}
}
[self startMonitoring];
}
- (BOOL)isInRange
{
if( device && [device remoteNameRequest:nil] == kIOReturnSuccess )
return true;
return false;
}
- (void)menuIconInRange
{
[statusItem setImage:inRangeImage];
[statusItem setAlternateImage:inRangeAltImage];
//[statusItem setTitle:@"O"];
}
- (void)menuIconOutOfRange
{
[statusItem setImage:outOfRangeImage];
[statusItem setAlternateImage:outOfRangeAltImage];
// [statusItem setTitle:@"X"];
}
- (BOOL)newVersionAvailable
{
NSURL *url = [NSURL URLWithString:@"http://reduxcomputing.com/download/Proximity.plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfURL:url];
NSArray *version = [[dict valueForKey:@"version"] componentsSeparatedByString:@"."];
int newVersionMajor = [[version objectAtIndex:0] intValue];
int newVersionMinor = [[version objectAtIndex:1] intValue];
if( thisVersionMajor < newVersionMajor || thisVersionMinor < newVersionMinor )
return YES;
return NO;
}
- (void)runInRangeScript
{
NSAppleScript *script;
NSDictionary *errDict;
NSAppleEventDescriptor *ae;
script = [[NSAppleScript alloc]
initWithContentsOfURL:[NSURL fileURLWithPath:[inRangeScriptPath stringValue]]
error:&errDict];
ae = [script executeAndReturnError:&errDict];
}
- (void)runOutOfRangeScript
{
NSAppleScript *script;
NSDictionary *errDict;
NSAppleEventDescriptor *ae;
script = [[NSAppleScript alloc]
initWithContentsOfURL:[NSURL fileURLWithPath:[outOfRangeScriptPath stringValue]]
error:&errDict];
ae = [script executeAndReturnError:&errDict];
}
- (void)startMonitoring
{
if( [monitoringEnabled state] == NSOnState )
{
timer = [NSTimer scheduledTimerWithTimeInterval:[timerInterval intValue]
target:self
selector:@selector(handleTimer:)
userInfo:nil
repeats:NO];
}
}
- (void)stopMonitoring
{
[timer invalidate];
}
- (void)userDefaultsLoad
{
NSUserDefaults *defaults;
NSData *deviceAsData;
defaults = [NSUserDefaults standardUserDefaults];
// Device
deviceAsData = [defaults objectForKey:@"device"];
if( [deviceAsData length] > 0 )
{
device = [NSKeyedUnarchiver unarchiveObjectWithData:deviceAsData];
[deviceName setStringValue:[NSString stringWithFormat:@"%@ (%@)",
[device name], [device addressString]]];
if( [self isInRange] )
{
priorStatus = InRange;
[self menuIconInRange];
}
else
{
priorStatus = OutOfRange;
[self menuIconOutOfRange];
}
}
//Timer interval
if( [[defaults stringForKey:@"timerInterval"] length] > 0 )
[timerInterval setStringValue:[defaults stringForKey:@"timerInterval"]];
// Out of range script path
if( [[defaults stringForKey:@"outOfRangeScriptPath"] length] > 0 )
[outOfRangeScriptPath setStringValue:[defaults stringForKey:@"outOfRangeScriptPath"]];
// In range script path
if( [[defaults stringForKey:@"inRangeScriptPath"] length] > 0 )
[inRangeScriptPath setStringValue:[defaults stringForKey:@"inRangeScriptPath"]];
// Check for updates on startup
BOOL updating = [defaults boolForKey:@"updating"];
if( updating ) {
[checkUpdatesOnStartup setState:NSOnState];
if( [self newVersionAvailable] )
{
if( NSRunAlertPanel( @"Proximity", @"A new version of Proximity is available for download.",
@"Close", @"Download", nil, nil ) == NSAlertAlternateReturn )
{
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://reduxcomputing.com/proximity/"]];
}
}
}
// Monitoring enabled
BOOL monitoring = [defaults boolForKey:@"enabled"];
if( monitoring ) {
[monitoringEnabled setState:NSOnState];
[self startMonitoring];
}
// Run scripts on startup
BOOL startup = [defaults boolForKey:@"executeOnStartup"];
if( startup )
{
[runScriptsOnStartup setState:NSOnState];
if( monitoring )
{
if( [self isInRange] ) {
[self runInRangeScript];
} else {
[self runOutOfRangeScript];
}
}
}
}
- (void)userDefaultsSave
{
NSUserDefaults *defaults;
NSData *deviceAsData;
defaults = [NSUserDefaults standardUserDefaults];
// Monitoring enabled
BOOL monitoring = ( [monitoringEnabled state] == NSOnState ? TRUE : FALSE );
[defaults setBool:monitoring forKey:@"enabled"];
// Update checking
BOOL updating = ( [checkUpdatesOnStartup state] == NSOnState ? TRUE : FALSE );
[defaults setBool:updating forKey:@"updating"];
// Execute scripts on startup
BOOL startup = ( [runScriptsOnStartup state] == NSOnState ? TRUE : FALSE );
[defaults setBool:startup forKey:@"executeOnStartup"];
// Timer interval
[defaults setObject:[timerInterval stringValue] forKey:@"timerInterval"];
// In range script
[defaults setObject:[inRangeScriptPath stringValue] forKey:@"inRangeScriptPath"];
// Out of range script
[defaults setObject:[outOfRangeScriptPath stringValue] forKey:@"outOfRangeScriptPath"];
// Device
if( device ) {
deviceAsData = [NSKeyedArchiver archivedDataWithRootObject:device];
[defaults setObject:deviceAsData forKey:@"device"];
}
[defaults synchronize];
}
#pragma mark -
#pragma mark Interface Methods
- (IBAction)changeDevice:(id)sender
{
IOBluetoothDeviceSelectorController *deviceSelector;
deviceSelector = [IOBluetoothDeviceSelectorController deviceSelector];
[deviceSelector runModal];
NSArray *results;
results = [deviceSelector getResults];
if( !results )
return;
device = [results objectAtIndex:0];
[deviceName setStringValue:[NSString stringWithFormat:@"%@ (%@)",
[device name],
[device addressString]]];
}
- (IBAction)checkConnectivity:(id)sender
{
[progressIndicator startAnimation:nil];
if( [self isInRange] )
{
[progressIndicator stopAnimation:nil];
NSRunAlertPanel( @"Found", @"Device is powered on and in range", nil, nil, nil, nil );
}
else
{
[progressIndicator stopAnimation:nil];
NSRunAlertPanel( @"Not Found", @"Device is powered off or out of range", nil, nil, nil, nil );
}
}
- (IBAction)checkForUpdates:(id)sender
{
if( [self newVersionAvailable] )
{
if( NSRunAlertPanel( @"Proximity", @"A new version of Proximity is available for download.",
@"Close", @"Download", nil, nil ) == NSAlertAlternateReturn )
{
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://reduxcomputing.com/proximity/"]];
}
}
else
{
NSRunAlertPanel( @"Proximity", @"You have the latest version.", @"Close", nil, nil, nil );
}
}
- (IBAction)donate:(id)sender
{
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://reduxcomputing.com/donate.php"]];
}
- (IBAction)enableMonitoring:(id)sender
{
// See windowWillClose: method
}
- (IBAction)inRangeScriptChange:(id)sender
{
NSOpenPanel *op = [NSOpenPanel openPanel];
[op runModalForDirectory:@"~" file:nil types:[NSArray arrayWithObject:@"scpt"]];
NSArray *filenames = [op filenames];
[inRangeScriptPath setStringValue:[filenames objectAtIndex:0]];
}
- (IBAction)inRangeScriptClear:(id)sender
{
[inRangeScriptPath setStringValue:@""];
}
- (IBAction)inRangeScriptTest:(id)sender
{
[self runInRangeScript];
}
- (IBAction)outOfRangeScriptChange:(id)sender
{
NSOpenPanel *op = [NSOpenPanel openPanel];
[op runModalForDirectory:@"~" file:nil types:[NSArray arrayWithObject:@"scpt"]];
NSArray *filenames = [op filenames];
[outOfRangeScriptPath setStringValue:[filenames objectAtIndex:0]];
}
- (IBAction)outOfRangeScriptClear:(id)sender
{
[outOfRangeScriptPath setStringValue:@""];
}
- (IBAction)outOfRangeScriptTest:(id)sender
{
[self runOutOfRangeScript];
}
- (void)showWindow:(id)sender
{
[NSApp activateIgnoringOtherApps:YES];
[prefsWindow makeKeyAndOrderFront:self];
[prefsWindow center];
[self stopMonitoring];
}
@end
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.