Created
May 30, 2025 22:39
-
-
Save grimpy/9a5a21bb71daf0b3acf225a6b4df2ec3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bytes" | |
"encoding/json" | |
"fmt" | |
"log" | |
"os" | |
"net/http" | |
"github.com/fsnotify/fsnotify" | |
"github.com/holoplot/go-evdev" | |
) | |
func send_to_ha(url string, token string, key string) { | |
data := map[string]string{ | |
"key": key, | |
} | |
jsonData, err := json.Marshal(data) | |
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData)) | |
if err != nil { | |
log.Printf("Failed to make request") | |
return | |
} | |
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) | |
client := &http.Client{} | |
resp, err := client.Do(req) | |
if err != nil { | |
log.Printf("Failed to post request\n") | |
return | |
} | |
defer resp.Body.Close() | |
log.Printf("Response status: %d\n", resp.StatusCode) | |
} | |
func readEvents(path string, keyEvents chan<- string) { | |
dev, err := evdev.Open(path) | |
if err != nil { | |
return | |
} | |
inputID, err := dev.InputID() | |
if err != nil { | |
log.Printf("Error loading input %s\n", path) | |
return | |
} | |
if inputID.Vendor != 0x4037 || inputID.Product != 0x2804 { | |
return | |
} | |
err = dev.Grab() | |
if err != nil { | |
log.Printf("Couldnt grab device %s\n", path) | |
return | |
} | |
name, err := dev.Name() | |
if err != nil { | |
log.Printf("Failed to read device name %s\n", path) | |
return | |
} | |
log.Printf("Reading events for %s\n", name) | |
for { | |
e, err := dev.ReadOne() | |
if err != nil { | |
log.Printf("Error reading from device: %v\n", err) | |
return | |
} | |
ts := fmt.Sprintf("Event: time %d.%06d", e.Time.Sec, e.Time.Usec) | |
switch e.Type { | |
case evdev.EV_KEY: | |
if e.Value == 1 { | |
log.Printf("%s, %s %d\n", ts, e.CodeName(), e.Value) | |
keyEvents <- e.CodeName() | |
} | |
} | |
} | |
} | |
func main() { | |
token := os.Getenv("HA_TOKEN") | |
url := os.Getenv("HA_URL") | |
if token == "" || url == "" { | |
log.Fatal("HA_TOKEN and HA_URL environment variables are required") | |
} | |
keyEvents := make(chan string) | |
devicePaths, err := evdev.ListDevicePaths() | |
if err != nil { | |
log.Fatalf("Cannot list device paths: %s\n", err) | |
return | |
} | |
for _, devPath := range devicePaths { | |
go readEvents(devPath.Path, keyEvents) | |
} | |
watcher, err := fsnotify.NewWatcher() | |
if err != nil { | |
log.Fatalf("Failed to create watches %s", err) | |
return | |
} | |
defer watcher.Close() | |
// Add a path. | |
err = watcher.Add("/dev/input") | |
if err != nil { | |
log.Fatal(err) | |
} | |
// Start listening for events. | |
for { | |
select { | |
case event, ok := <-watcher.Events: | |
if !ok { | |
return | |
} | |
if event.Has(fsnotify.Chmod) { | |
log.Printf("Permissions set for file: %s\n", event.Name) | |
go readEvents(event.Name, keyEvents) | |
} | |
case err, ok := <-watcher.Errors: | |
if !ok { | |
return | |
} | |
log.Println("error:", err) | |
case key, ok := <-keyEvents: | |
if !ok { | |
return | |
} | |
send_to_ha(url, token, key) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment