From 0badf20ff2a8e6ac952059c35c3d2c7efeb40086 Mon Sep 17 00:00:00 2001 From: wgroeneveld Date: Wed, 1 Feb 2023 21:20:35 +0100 Subject: [PATCH] create a macos launchd file, use channels to wait for BLE con --- README.md | 4 ++ com.brainbaking.PhomemoPrinter.plist | 28 +++++++++++ main.go | 69 ++++++++++++++++++---------- 3 files changed, 78 insertions(+), 23 deletions(-) create mode 100644 com.brainbaking.PhomemoPrinter.plist diff --git a/README.md b/README.md index aba91f0..8dfb556 100644 --- a/README.md +++ b/README.md @@ -14,3 +14,7 @@ If you're on macOS, the Python pybluez Bluetooth drivers don't work (well) on th The script checks a folder for files (intended to be set up as a cron job), if there are any, sends them to the printer (if detected), **and deletes them**. See `main.go`, you'll probably want to edit some variables. I hacked everything together in a day for our specific case. + +## Launchd service + +To install as a `launchd` service (mac's "cron"), copy the binary to `/usr/local/bin` and the file `com.brainbaking.PhomemoPrinter.plist` to `~/Library/LaunchAgents`. Then, in a terminal, type `launchctl load com.brainbaking.PhomemoPrinter.plist`. diff --git a/com.brainbaking.PhomemoPrinter.plist b/com.brainbaking.PhomemoPrinter.plist new file mode 100644 index 0000000..3689770 --- /dev/null +++ b/com.brainbaking.PhomemoPrinter.plist @@ -0,0 +1,28 @@ + + + + + Label + com.brainbaking.phomemoprinter + + ProgramArguments + + /usr/local/bin/phomemoprinter + + + Nice + 1 + + StartInterval + 60 + + RunAtLoad + + + StandardErrorPath + /tmp/PhomemoPrinter.err + + StandardOutPath + /tmp/PhomemoPrinter.out + + \ No newline at end of file diff --git a/main.go b/main.go index 2db1503..9a3324d 100644 --- a/main.go +++ b/main.go @@ -6,6 +6,7 @@ import ( "os" "os/exec" "strconv" + "strings" "time" "tinygo.org/x/bluetooth" ) @@ -18,29 +19,40 @@ func main() { inDir := home + phomemoFolder files, err := os.ReadDir(inDir) - must(phomemoFolder, err) + must(phomemoFolder + " does not exist", err) if len(files) == 0 { - log.Printf("No files to print found in %s. Quitting.\n", inDir) + log.Printf("No files to print found in %s, nothing to do. Quitting.\n", inDir) os.Exit(0) } - // Enable BLE interface. - must("enable BLE stack", adapter.Enable()) + must("Enable Bluetooth stack", adapter.Enable()) - // Start scanning. Use this to figure out your device's UUID. Phomemo uses a non-random one. - println("scanning...") - var phomemoAddress bluetooth.ScanResult - err = adapter.Scan(func(adapter *bluetooth.Adapter, device bluetooth.ScanResult) { - if device.LocalName() == "Mr.in_M02" { - phomemoAddress = device + log.Println("Scanning for Bluetooth devices...") + ch := make(chan bluetooth.ScanResult, 1) + timeout := make(chan bool, 1) + go func() { + time.Sleep(10 * time.Second) + timeout <- true + }() - println("found device: ", device.Address.String(), device.RSSI, device.LocalName()) - adapter.StopScan() - } - }) - must("start scan", err) + go func() { + err = adapter.Scan(func(adapter *bluetooth.Adapter, device bluetooth.ScanResult) { + if device.LocalName() == "Mr.in_M02" { + ch <- device + adapter.StopScan() + } + }) + must("start scan", err) + }() + + select { + case device := <- ch: + log.Println("Found device: ", device.Address.String(), device.RSSI, device.LocalName()) + tryToPrint(device, inDir, files) + case <- timeout: + log.Fatal("Timeout trying to locate Phomemo M02, is it on? Quitting.") + } - tryToPrint(phomemoAddress, inDir, files) } func tryToPrint(phomemoAddress bluetooth.ScanResult, dir string, files []os.DirEntry) { @@ -66,31 +78,42 @@ func tryToPrint(phomemoAddress bluetooth.ScanResult, dir string, files []os.DirE chars, err := srvc.DiscoverCharacteristics(nil) must("failed to discover characteristics of service", err) - dumpFilter("phomemo-filter.py") + pyfilterloc := dir + "/" + "phomemo-filter.py" + dumpFilter(pyfilterloc) defer func() { - os.RemoveAll("phomemo-filter.py") + os.RemoveAll(pyfilterloc) }() // 3 characteristics to discover 0000ff01, 0000ff02, and 0000ff03 for _, file := range files { filePath := dir + "/" + file.Name() - writeData(filePath, chars[1]) // 0000ff02-... - readResult(chars[0]) // 0000ff01-... - os.RemoveAll(filePath) + if isPossibleToPrint(filePath) { + writeData(pyfilterloc, filePath, chars[1]) // 0000ff02-... + readResult(chars[0]) // 0000ff01-... + os.RemoveAll(filePath) + } } log.Println("-- DONE") } +func isPossibleToPrint(filename string) bool { + return strings.HasSuffix(filename, ".jpg") || + strings.HasSuffix(filename, ".JPG") || + strings.HasSuffix(filename, ".png") || + strings.HasSuffix(filename, ".PNG") +} + func dumpFilter(filename string) { err := os.WriteFile(filename, phomemofilter.Pyfilter, 0666) must("unable to dump python filter for use", err) } -func writeData(path string, char bluetooth.DeviceCharacteristic) { +func writeData(pyfilterloc string, path string, char bluetooth.DeviceCharacteristic) { // first, it needs to be prepared for the printer pathpho := path + ".pho" - argstr := []string{"-c", "python phomemo-filter.py " + path + " > " + pathpho} + argstr := []string{"-c", "/usr/local/bin/python " + pyfilterloc + " " + path + " > " + pathpho} + log.Println("args", argstr) _, err := exec.Command("/bin/zsh", argstr...).Output() must("something went wrong while filtering phomemo data py", err)