package main import ( phomemofilter "brainbaking.com/phomemoprinter/filter" "log" "os" "os/exec" "strconv" "time" "tinygo.org/x/bluetooth" ) var adapter = bluetooth.DefaultAdapter var phomemoFolder = "/Downloads/phomemo" func main() { home, _ := os.UserHomeDir() inDir := home + phomemoFolder files, err := os.ReadDir(inDir) must(phomemoFolder, err) if len(files) == 0 { log.Printf("No files to print found in %s. Quitting.\n", inDir) os.Exit(0) } // Enable BLE interface. must("enable BLE 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 println("found device: ", device.Address.String(), device.RSSI, device.LocalName()) adapter.StopScan() } }) must("start scan", err) tryToPrint(phomemoAddress, inDir, files) } func tryToPrint(phomemoAddress bluetooth.ScanResult, dir string, files []os.DirEntry) { var phomemo *bluetooth.Device phomemo, err := adapter.Connect(phomemoAddress.Address, bluetooth.ConnectionParams{}) must("failed to connect to adapter", err) log.Println("connected to ", phomemoAddress.Address.String()) defer func() { if err := phomemo.Disconnect(); err != nil { log.Println(err) } else { log.Println("disconnected") } }() srvcs, err := phomemo.DiscoverServices(nil) must("failed to discover service", err) log.Println("Discovering all services on device...") srvc := srvcs[0] // there's only one (0000ff00-...) anyway log.Println("- service", srvc.UUID().String()) chars, err := srvc.DiscoverCharacteristics(nil) must("failed to discover characteristics of service", err) dumpFilter("phomemo-filter.py") defer func() { os.RemoveAll("phomemo-filter.py") }() // 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) } log.Println("-- DONE") } 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) { // first, it needs to be prepared for the printer pathpho := path + ".pho" argstr := []string{"-c", "python phomemo-filter.py " + path + " > " + pathpho} _, err := exec.Command("/bin/zsh", argstr...).Output() must("something went wrong while filtering phomemo data py", err) data, _ := os.ReadFile(pathpho) log.Printf("-- writing file %s to characteristic %s\n", path, char.UUID().String()) _, err = char.WriteWithoutResponse(data) if err != nil { log.Println(" ", err.Error()) } time.Sleep(1 * time.Second) os.RemoveAll(pathpho) } func readResult(char bluetooth.DeviceCharacteristic) { log.Println("-- reading from to characteristic", char.UUID().String()) buf := make([]byte, 28) n, err := char.Read(buf) if err != nil { log.Println(" ", err.Error()) } else { log.Println(" data bytes", strconv.Itoa(n)) log.Println(" value =", buf[:n]) } time.Sleep(1 * time.Second) } func must(action string, err error) { if err != nil { panic("failed to " + action + ": " + err.Error()) } }