summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/build.yml34
-rw-r--r--README.md50
-rw-r--r--ddcutil-daemon.json4
-rw-r--r--flake.lock25
-rw-r--r--flake.nix39
-rw-r--r--go.mod3
-rw-r--r--main.go176
7 files changed, 331 insertions, 0 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..3961181
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,34 @@
+name: "Build"
+on:
+ pull_request:
+ push:
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2.4.0
+ - uses: cachix/install-nix-action@v15
+ with:
+ extra_nix_config: |
+ access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
+ - run: nix build
+ - name: Create Release
+ id: create_release
+ uses: actions/create-release@v1
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ tag_name: ${{ github.ref }}
+ release_name: Release ${{ github.ref }}
+ draft: false
+ prerelease: false
+ - name: Upload Release Asset
+ id: upload-release-asset
+ uses: actions/upload-release-asset@v1
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ with:
+ upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
+ asset_path: ./result/bin/ddcutil-daemon
+ asset_name: ddcutil-daemon
+ asset_content_type: application/octet-stream
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..6d97db7
--- /dev/null
+++ b/README.md
@@ -0,0 +1,50 @@
+# Description
+
+HTTP service to control monitor brightness.
+
+# Requirements
+
+* go 1.17.11
+* ddcutil 1.2.2
+* linux 5.13.16
+
+# Build
+
+``` shell
+nix build
+```
+
+# Run
+
+```
+sudo result/bin/ddcutil-daemon
+```
+
+The `ddcutil` binary should run with root privileges, so we use `sudo`.
+
+# Usage
+
+Get current brightness cached value:
+```shell
+curl 127.0.0.1:49281/set
+```
+
+Set brightness to specific value:
+```shell
+curl --request POST --data '{'value': 5}' 127.0.0.1:49281/set
+```
+
+Increase brightness:
+```shell
+curl --request POST --data '{"value": 5}' 127.0.0.1:49281/increase
+```
+
+Decrease brightness:
+```shell
+curl --request POST --data '{"value": 5}' 127.0.0.1:49281/decrease
+```
+
+Toggle brightness between current and minimal values:
+```shell
+curl --request POST 127.0.0.1:49281/toggle
+```
diff --git a/ddcutil-daemon.json b/ddcutil-daemon.json
new file mode 100644
index 0000000..33e9a05
--- /dev/null
+++ b/ddcutil-daemon.json
@@ -0,0 +1,4 @@
+{
+ "listen": "127.0.0.1:49281",
+ "vcp": "10"
+}
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000..858d802
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,25 @@
+{
+ "nodes": {
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1697886341,
+ "narHash": "sha256-AdE67xPty9M9wn36nPVp6aDntIdigrs7UbyaGv1VAaM=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "44881e03af1c730cbb1d72a4d41274a2c957813a",
+ "type": "github"
+ },
+ "original": {
+ "id": "nixpkgs",
+ "type": "indirect"
+ }
+ },
+ "root": {
+ "inputs": {
+ "nixpkgs": "nixpkgs"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..44823ef
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,39 @@
+{
+ description = "HTTP service to control monitor brightness";
+
+ outputs = { self, nixpkgs, ... }:
+ let system = "x86_64-linux";
+ in {
+ packages.${system} = {
+ default = nixpkgs.legacyPackages.${system}.callPackage
+ ({ lib, go, buildGoModule }:
+ buildGoModule rec {
+ pname = "ddcutil-daemon";
+ version = "0.0.1";
+ src = ./.;
+ # preConfigure phase to compile a statically linked executable
+ preConfigure = ''
+ export CGO_ENABLED=0
+ export GOOS=linux
+ export GOARCH=amd64
+ '';
+ ldflags = let t = "github.com/kitnil/ddcutil-daemon";
+ in [
+ "-s" # stripped binary
+ "-X ${t}.Version=${version}"
+ "-X ${t}.Branch=unknown"
+ "-X ${t}.BuildUser=nix@nixpkgs"
+ "-X ${t}.BuildDate=unknown"
+ "-X ${t}.GoVersion=${lib.getVersion go}"
+ ];
+ vendorSha256 = null;
+ meta = with lib; {
+ description = "HTTP service to control monitor brightness.";
+ homepage = "https://github.com/kitnil/ddcutil-daemon";
+ license = licenses.asl20;
+ platforms = platforms.unix;
+ };
+ }) { };
+ };
+ };
+}
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..f018c57
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,3 @@
+module github.com/kitnil/ddcutil-daemon
+
+go 1.17
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..60de258
--- /dev/null
+++ b/main.go
@@ -0,0 +1,176 @@
+package main
+
+import (
+ "encoding/json"
+ "io"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "os"
+ "os/exec"
+ "strconv"
+ "strings"
+)
+
+type Configuration struct {
+ Listen string
+ Vcp string
+}
+
+var configuration = Configuration{
+ Listen: "127.0.0.1:49281",
+ Vcp: "10"}
+
+type Brightness struct {
+ Lock bool
+ Value int
+ ToggledValue int
+}
+
+var currentBrightness Brightness
+
+func update() {
+ if currentBrightness.Lock == false {
+ currentBrightness.Lock = true
+ cmd := exec.Command("ddcutil", "getvcp", "--brief", configuration.Vcp)
+ log.Println(cmd.String())
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ log.Println(err)
+ return
+ }
+ outString := strings.Split(strings.Trim(string(out), "\n"), " ")
+ currentBrightness.Value, err = strconv.Atoi(outString[len(outString)-2])
+ if err != nil {
+ log.Println(err)
+ return
+ }
+ log.Println("Current brightness is", currentBrightness.Value)
+ currentBrightness.Lock = false
+ } else {
+ log.Println("Active lock, no operation performed")
+ return
+ }
+}
+
+func get(w http.ResponseWriter, r *http.Request) {
+ if r.Method == "GET" {
+ log.Println("Current brightness cached value is",
+ currentBrightness.Value)
+ }
+}
+
+func ddcutilSetBrightness(brightness Brightness) {
+ if currentBrightness.Lock == false {
+ currentBrightness.Lock = true
+ cmd := exec.Command("ddcutil", "setvcp", configuration.Vcp,
+ strconv.Itoa(brightness.Value))
+ log.Println(cmd.String())
+ _, err := cmd.CombinedOutput()
+ if err != nil {
+ log.Println(err)
+ return
+ }
+ currentBrightness.Value = brightness.Value
+ currentBrightness.Lock = false
+ } else {
+ log.Println("Active lock, no operation performed")
+ return
+ }
+}
+
+func set(w http.ResponseWriter, r *http.Request) {
+ if r.Method == "POST" {
+ body, err := io.ReadAll(r.Body)
+ if err != nil {
+ log.Println(err)
+ return
+ }
+ var brightness Brightness
+ json.Unmarshal([]byte(body), &brightness)
+ ddcutilSetBrightness(brightness)
+ }
+}
+
+func decrease(w http.ResponseWriter, r *http.Request) {
+ if r.Method == "POST" {
+ body, err := io.ReadAll(r.Body)
+ if err != nil {
+ log.Println(err)
+ return
+ }
+ var brightness Brightness
+ json.Unmarshal([]byte(body), &brightness)
+ newValue := Brightness{Value: currentBrightness.Value - brightness.Value}
+ if newValue.Value < 0 {
+ log.Println("Brightness is minimum")
+ } else {
+ ddcutilSetBrightness(newValue)
+ log.Println("Current brightness is", currentBrightness.Value)
+ }
+ } else {
+ log.Println("Active lock, no operation performed")
+ return
+ }
+}
+
+func increase(w http.ResponseWriter, r *http.Request) {
+ if r.Method == "POST" {
+ body, err := io.ReadAll(r.Body)
+ if err != nil {
+ log.Println(err)
+ return
+ }
+ var brightness Brightness
+ json.Unmarshal([]byte(body), &brightness)
+ newValue := Brightness{Value: currentBrightness.Value + brightness.Value}
+ if newValue.Value > 100 {
+ log.Println("Brightness is maximum")
+ } else {
+ ddcutilSetBrightness(newValue)
+ log.Println("Current brightness is", currentBrightness.Value)
+ }
+ } else {
+ log.Println("Active lock, no operation performed")
+ return
+ }
+}
+
+func toggle(w http.ResponseWriter, r *http.Request) {
+ if r.Method == "POST" {
+ if currentBrightness.Value == 0 {
+ ddcutilSetBrightness(Brightness{Value: currentBrightness.ToggledValue})
+ log.Println("Current brightness is", currentBrightness.Value)
+ } else {
+ currentBrightness.ToggledValue = currentBrightness.Value
+ ddcutilSetBrightness(Brightness{Value: 0})
+ log.Println("Current brightness is", currentBrightness.Value)
+ }
+ }
+}
+
+func main() {
+ jsonFile, err := os.Open("ddcutil-daemon.json")
+ if err != nil {
+ log.Fatalln(err)
+ }
+ byteValue, err := ioutil.ReadAll(jsonFile)
+ if err != nil {
+ log.Fatalln(err)
+ }
+ var configuration Configuration
+ json.Unmarshal(byteValue, &configuration)
+ jsonFile.Close()
+
+ currentBrightness.Lock = false
+ update()
+ http.HandleFunc("/update", func(w http.ResponseWriter, r *http.Request) {
+ update()
+ })
+ http.HandleFunc("/get", get)
+ http.HandleFunc("/set", set)
+ http.HandleFunc("/decrease", decrease)
+ http.HandleFunc("/increase", increase)
+ http.HandleFunc("/toggle", toggle)
+ log.Fatal(http.ListenAndServe(configuration.Listen, nil))
+}