Created
January 14, 2021 15:14
-
-
Save olimsaidov/41f79b2e203270574af85e74323b3be1 to your computer and use it in GitHub Desktop.
Clojure YeeLight Controller
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
#!/usr/bin/env bb | |
(ns app.yeelight | |
(:import [java.net DatagramPacket DatagramSocket | |
InetAddress URI Socket]) | |
(:require [clojure.string :as str] | |
[clojure.walk :as walk] | |
[clojure.java.io :as io] | |
[cheshire.core :as json] | |
[clojure.tools.cli :as cli])) | |
(defn parse-device | |
[device] | |
(let [lines (->> (str/split device #"\r\n") | |
(remove empty?))] | |
(->> (mapv (fn [line] (let [match (re-find #"(.*): (.*)" line)] | |
(when (= 3 (count match)) | |
[(str/lower-case (match 1)) | |
(match 2)]))) | |
lines) | |
(remove nil?) | |
(into {}) | |
walk/keywordize-keys))) | |
(defn discover | |
[] | |
(let [send-data (.getBytes (str/join "\r\n" ["M-SEARCH * HTTP/1.1" | |
"Host: 239.255.255.250:1982" | |
"MAN: \"ssdp:discover\"" | |
"ST: wifi_bulb"])) | |
receive-data (byte-array 1024) | |
send-packet (DatagramPacket. send-data (count send-data) (InetAddress/getByName "239.255.255.250") 1982) | |
client-socket (doto (DatagramSocket.) (.send send-packet)) | |
receive-packet (DatagramPacket. receive-data (count receive-data))] | |
(parse-device (do (.receive client-socket receive-packet) | |
(new String (.getData receive-packet)))))) | |
(defn call-method | |
[uri method params] | |
(with-open [socket (Socket. (.getHost (URI. uri)) (.getPort (URI. uri))) | |
writer (io/writer (.getOutputStream socket)) | |
reader (io/reader (.getInputStream socket))] | |
(.write writer (str (json/encode {:id (rand-int 10000) | |
:method method | |
:params params}) | |
"\r\n")) | |
(.flush writer) | |
(json/decode (.readLine reader) true))) | |
(defn rgb->int | |
[r g b] | |
(+ (* 65536 r) (* 256 g) b)) | |
(def cli-options | |
[["-r" "--red BYTE" "Red color" :default (rand-int 256) :parse-fn #(Integer/parseInt %) :validate [#(<= 0 % 255) "Must be a number between 0 and 255"]] | |
["-g" "--green BYTE" "Green color" :default (rand-int 256) :parse-fn #(Integer/parseInt %) :validate [#(<= 0 % 255) "Must be a number between 0 and 255"]] | |
["-b" "--blue BYTE" "Blue color" :default (rand-int 256) :parse-fn #(Integer/parseInt %) :validate [#(<= 0 % 255) "Must be a number between 0 and 255"]]]) | |
(let [options (:options (cli/parse-opts *command-line-args* cli-options))] | |
(call-method (:location (discover)) :set_rgb | |
[(rgb->int (:red options) (:green options) (:blue options)) "smooth" 400])) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment