commit 8b069b9e827ea846f18206cf0acd56ce03a80aee
parent 3af21cdd895bdc92af9fb4f4df9f654736fa47d2
Author: Leah (ctucx) <leah@ctu.cx>
Date: Sat, 2 Apr 2022 22:58:24 +0200
parent 3af21cdd895bdc92af9fb4f4df9f654736fa47d2
Author: Leah (ctucx) <leah@ctu.cx>
Date: Sat, 2 Apr 2022 22:58:24 +0200
pkgs: add SpeakerDaemon (tiny daemon that switches my desktop speakers on or off based on sleep-state of the mac)
1 file changed, 133 insertions(+), 0 deletions(-)
A
|
133
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
diff --git a/pkgs/SpeakerDaemon/default.nix b/pkgs/SpeakerDaemon/default.nix @@ -0,0 +1,133 @@ +{stdenv, runCommand, writeText, ...}: + +let + secrets = import ../../secrets; + + SpeakerDaemon = writeText "speakerDaemon.c" '' + #include <ctype.h> + #include <stdlib.h> + #include <stdio.h> + + #include <mach/mach_port.h> + #include <mach/mach_interface.h> + #include <mach/mach_init.h> + + #include <IOKit/pwr_mgt/IOPMLib.h> + #include <IOKit/IOMessage.h> + + #include <curl/curl.h> + + io_connect_t root_port; // a reference to the Root Power Domain IOService + + void MySleepCallBack( void * refCon, io_service_t service, natural_t messageType, void * messageArgument ) { + CURL *curl; + CURLcode res; + FILE *dummy_writer = fopen("/dev/null", "w"); + + curl_global_init(CURL_GLOBAL_ALL); + + switch ( messageType ) { + case kIOMessageCanSystemSleep: + IOAllowPowerChange( root_port, (long)messageArgument ); + break; + + case kIOMessageSystemWillSleep: + printf("Sleep-Event!\n"); + + curl = curl_easy_init(); + if (curl) { + curl_easy_setopt(curl, CURLOPT_WRITEDATA, dummy_writer); + curl_easy_setopt(curl, CURLOPT_URL, "http://10.0.0.1:5000"); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "{\"accessToken\": \"${secrets.hosts.lollo.smartied.accessToken}\", \"type\": \"SwitchStateAction\", \"deviceName\": \"modbus-20\", \"relay\": 0, \"state\": false}"); + + res = curl_easy_perform(curl); + if (res != CURLE_OK) fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); + + curl_easy_cleanup(curl); + } + + IOAllowPowerChange(root_port, (long)messageArgument ); + break; + + case kIOMessageSystemWillPowerOn: + //System has started the wake up process... + break; + + case kIOMessageSystemHasPoweredOn: + printf("WakeUp-Event!\n"); + + curl = curl_easy_init(); + if (curl) { + curl_easy_setopt(curl, CURLOPT_WRITEDATA, dummy_writer); + curl_easy_setopt(curl, CURLOPT_URL, "http://10.0.0.1:5000"); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "{\"accessToken\": \"${secrets.hosts.lollo.smartied.accessToken}\", \"type\": \"SwitchStateAction\", \"deviceName\": \"modbus-20\", \"relay\": 0, \"state\": true}"); + + res = curl_easy_perform(curl); + if (res != CURLE_OK) fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); + + curl_easy_cleanup(curl); + } + break; + + default: + break; + } + curl_global_cleanup(); + } + + + int main( int argc, char **argv ) { + // notification port allocated by IORegisterForSystemPower + IONotificationPortRef notifyPortRef; + + // notifier object, used to deregister later + io_object_t notifierObject; + // this parameter is passed to the callback + void* refCon; + + // register to receive system sleep notifications + root_port = IORegisterForSystemPower( refCon, ¬ifyPortRef, MySleepCallBack, ¬ifierObject ); + if ( root_port == 0 ) { + printf("IORegisterForSystemPower failed\n"); + return 1; + } + + // add the notification port to the application runloop + CFRunLoopAddSource( CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(notifyPortRef), kCFRunLoopCommonModes ); + + /* Start the run loop to receive sleep notifications. Don't call CFRunLoopRun if this code + is running on the main thread of a Cocoa or Carbon application. Cocoa and Carbon + manage the main thread's run loop for you as part of their event handling + mechanisms. + */ + CFRunLoopRun(); + + //Not reached, CFRunLoopRun doesn't return in this case. + return (0); + } + ''; + + buildSymlinks = runCommand "macvim-build-symlinks" {} '' + mkdir -p $out/bin + ln -s /usr/bin/gcc $out/bin + ''; + +in stdenv.mkDerivation { + name = "SpeakerDaemon"; + src = ./.; + + nativeBuildInputs = [ buildSymlinks ]; + + sandboxProfile = '' + (allow file-read* file-write* process-exec mach-lookup) + ; block homebrew dependencies + (deny file-read* file-write* process-exec mach-lookup (subpath "/usr/local") (with no-log)) + ''; + + buildPhase = "gcc -framework IOKit -framework Cocoa -lcurl -o SpeakerDaemon ${SpeakerDaemon}"; + + installPhase = '' + mkdir -p $out/bin + cp SpeakerDaemon $out/bin/ + ''; +}