;; visualiser.el (load-file "~/.emacs.d/elpa/dash-20240510.1327/dash.elc") (load-file "~/.emacs.d/elpa/mqtt-mode-20180611.1735/mqtt-mode.elc") (require 'dash) (require 'mqtt-mode) (toggle-debug-on-error) ;; directory variables (defconst graphviz-command "circo") (defconst graphviz-graph-output-format "svg") (defconst graphviz-graph-output-dir "graphs/") (defconst graphviz-image-output-dir (concat graphviz-graph-output-format "s/")) (defconst working-directory "~/Applications/listeningdaemon/visualiser/") (load-file (concat working-directory "secrets.el")) ;; colors ;; (defconst on-color "black" "The default color for objects which are active") (defconst off-color "invis" "The default color for objects which are not active") (defvar gesture-color "black" "color to outline objects involved in a gesture") (defvar colors '("red" "green" "blue" "magenta" "yellow" "orange" "purple" "cyan") "colors for the nodes and edges to choose from") ;;; nodes ;; default colors (defvar fan-one-color off-color) (defvar fan-two-color off-color) (defvar radio-one-color off-color) (defvar lamp-one-color off-color) (defvar lamp-two-color off-color) (defvar printer-one-color off-color) (defvar printer-two-color off-color) (defvar fan-one-gesture-color fan-one-color) (defvar fan-two-gesture-color fan-two-color) (defvar radio-one-gesture-color radio-one-color) (defvar lamp-one-gesture-color lamp-one-color) (defvar lamp-two-gesture-color lamp-two-color) (defvar printer-one-gesture-color printer-one-color) (defvar printer-two-gesture-color printer-two-color) ;;; edges ;; default colors (defvar fan-one-fan-two-color off-color) (defvar fan-one-radio-one-color off-color) (defvar fan-one-lamp-one-color off-color) (defvar fan-one-lamp-two-color off-color) (defvar fan-one-printer-one-color off-color) (defvar fan-one-printer-two-color off-color) (defvar fan-two-radio-one-color off-color) (defvar fan-two-lamp-one-color off-color) (defvar fan-two-lamp-two-color off-color) (defvar fan-two-printer-one-color off-color) (defvar fan-two-printer-two-color off-color) (defvar radio-one-lamp-one-color off-color) (defvar radio-one-lamp-two-color off-color) (defvar radio-one-printer-one-color off-color) (defvar radio-one-printer-two-color off-color) (defvar lamp-one-lamp-two-color off-color) (defvar lamp-one-printer-one-color off-color) (defvar lamp-one-printer-two-color off-color) (defvar lamp-two-printer-one-color off-color) (defvar lamp-two-printer-two-color off-color) (defvar printer-one-printer-two-color off-color) (setq snapshot 10000) (defun turn-object-on (object) "Turn an object on" nil nil (setq on-color (elt colors (random (length colors)))) (cond ((equal object 'fan-one) (setq fan-one-color on-color) (format-graph)) ((equal object 'fan-two) (setq fan-two-color on-color) (format-graph)) ((equal object 'lamp-one) (setq lamp-one-color on-color) (format-graph)) ((equal object 'lamp-two) (setq lamp-two-color on-color) (format-graph)) ((equal object 'radio-one) (setq radio-one-color on-color) (format-graph)) ((equal object 'printer-one) (setq printer-one-color on-color) (format-graph)) ((equal object 'printer-two) (setq printer-two-color on-color) (format-graph)))) (defun turn-object-off (object) "Turn an object off" nil nil (cond ((equal object 'fan-one) (setq fan-one-color off-color) (format-graph)) ((equal object 'fan-two) (setq fan-two-color off-color) (format-graph)) ((equal object 'lamp-one) (setq lamp-one-color off-color) (format-graph)) ((equal object 'lamp-two) (setq lamp-two-color off-color) (format-graph)) ((equal object 'radio-one) (setq radio-one-color off-color) (format-graph)) ((equal object 'printer-one) (setq printer-one-color off-color) (format-graph)) ((equal object 'printer-two) (setq printer-one-color off-color) (format-graph)))) (defun graph-write-file-quietly () "Write the graph buffer to a graphviz file quietly" (let ((inhibit-message t)) (write-file (concat working-directory graphviz-graph-output-dir "graph" (number-to-string snapshot) ".dot") t))) (defun format-graph-image-numbered () "format the numbered image of the graph quietly, for the .gif" (let ((inhibit-message t)) (shell-command (concat graphviz-command " -T" graphviz-graph-output-format " " working-directory graphviz-graph-output-dir (concat "graph" (number-to-string snapshot) ".dot") " -o " working-directory graphviz-image-output-dir (concat "graph" (number-to-string snapshot) "." graphviz-graph-output-format))))) (defun format-graph-image-main () "format the image of the main graph quietly" nil nil (let ((inhibit-message t)) (shell-command (concat graphviz-command " -T" graphviz-graph-output-format " " working-directory graphviz-graph-output-dir (concat "graph" (number-to-string snapshot) ".dot") " -o " ;; working-directory "main." graphviz-graph-output-format ;; output the generated image to /var/www/ so that the webpage stays updated "/var/www/img/main." graphviz-graph-output-format )))) (defun format-graph () "Series of functions to format the graph to display in the browser and ultimately turn into a .gif" nil nil ;; preprocess graph (shell-command (concat "cpp -DFAN_ONE=" fan-one-color " " "-DFAN_TWO=" fan-two-color " " "-DRADIO_ONE=" radio-one-color " " "-DLAMP_ONE=" lamp-one-color " " "-DLAMP_TWO=" lamp-two-color " " "-DPRINTER_ONE=" printer-one-color " " "-DPRINTER_TWO=" printer-two-color " " "-DFAN_ONE_GESTURE=" fan-one-gesture-color " " "-DFAN_TWO_GESTURE=" fan-two-gesture-color " " "-DRADIO_ONE_GESTURE=" radio-one-gesture-color " " "-DLAMP_ONE_GESTURE=" lamp-one-gesture-color " " "-DLAMP_TWO_GESTURE=" lamp-two-gesture-color " " "-DPRINTER_ONE_GESTURE=" printer-one-gesture-color " " "-DPRINTER_TWO_GESTURE=" printer-two-gesture-color " " "-DFAN_ONE_FAN_TWO=" fan-one-fan-two-color " " "-DFAN_ONE_RADIO_ONE=" fan-one-radio-one-color " " "-DFAN_ONE_LAMP_ONE=" fan-one-lamp-one-color " " "-DFAN_ONE_LAMP_TWO=" fan-one-lamp-two-color " " "-DFAN_ONE_PRINTER_ONE=" fan-one-printer-one-color " " "-DFAN_ONE_PRINTER_TWO=" fan-one-printer-two-color " " "-DFAN_TWO_RADIO_ONE=" fan-two-radio-one-color " " "-DFAN_TWO_LAMP_ONE=" fan-two-lamp-one-color " " "-DFAN_TWO_LAMP_TWO=" fan-two-lamp-two-color " " "-DFAN_TWO_PRINTER_ONE=" fan-two-printer-one-color " " "-DFAN_TWO_PRINTER_TWO=" fan-two-printer-two-color " " "-DRADIO_ONE_LAMP_ONE=" radio-one-lamp-one-color " " "-DRADIO_ONE_LAMP_TWO=" radio-one-lamp-two-color " " "-DRADIO_ONE_PRINTER_ONE=" radio-one-printer-one-color " " "-DRADIO_ONE_PRINTER_TWO=" radio-one-printer-two-color " " "-DLAMP_ONE_LAMP_TWO=" lamp-one-lamp-two-color " " "-DLAMP_ONE_PRINTER_ONE=" lamp-one-printer-one-color " " "-DLAMP_ONE_PRINTER_TWO=" lamp-one-printer-two-color " " "-DLAMP_TWO_PRINTER_ONE=" lamp-two-printer-one-color " " "-DLAMP_TWO_PRINTER_TWO=" lamp-two-printer-two-color " " "-DPRINTER_ONE_PRINTER_TWO=" printer-one-printer-two-color " " working-directory "main.dot") (concat "graph" (number-to-string snapshot) ".dot") "*Error*") (switch-to-buffer-other-window (concat "graph" (number-to-string snapshot) ".dot")) (set-mark (point)) (forward-line 6) (kill-region 0 (point) t) (graph-write-file-quietly) ;; create a backup of the graph, for the .gif (format-graph-image-numbered) ;; change main.png for displaying in the browser (format-graph-image-main) (setq snapshot (+ snapshot 1))) ;; (illuminate-edges '("transform" "printer" "one" "fan" "two") "1") (defun illuminate-edges (topic payload) "Function to illuminate the edges of the graph" nil nil (setq on-color (elt colors (random (length colors)))) (let ((payload (string-limit payload 1))) (let ((from-object (string-join (list (cadr topic) (caddr topic)) "-")) (to-object (string-join (list (cadddr topic) (car (last topic))) "-"))) (message "From: %s" from-object) (message "To: %s" to-object) (when (string-equal payload "1") (set (intern (concat from-object "-" to-object "-color")) on-color) (set (intern (concat to-object "-" from-object "-color")) on-color)) (when (string-equal payload "0") (set (intern (concat from-object "-" to-object "-color")) off-color) (set (intern (concat to-object "-" from-object "-color")) off-color)) (format-graph)))) ;; (illuminate-gesture '("main" "gesture" "printer" "one") "0") ;; (illuminate-gesture '("main" "gesture" "printer" "one") "x") (defun illuminate-gesture (topic payload) "Function to illuminate the outlines of nodes on the graph" nil nil (setq on-color (elt colors (random (length colors)))) (let ((payload (string-limit payload 1))) (let ((gesture-object (string-join (list (elt topic 2) (elt topic 3)) "-"))) (message "Gesturing towards: %s" gesture-object) (if (string-equal payload "0") (set (intern (concat gesture-object "-gesture-color")) off-color) (set (intern (concat gesture-object "-gesture-color")) gesture-color)) (format-graph)))) (defun illuminate-nodes (topic payload) "Function to illuminate the nodes on the graph, a decision tree" nil nil (setq on-color (elt colors (random (length colors)))) (let ((payload (string-limit payload 1))) ;;(message "Topic: %s. Payload %s." topic payload) (cond ((and (member "fan" topic) (member "one" topic) (string-equal "1" payload)) (turn-object-on 'fan-one) (message "Fan one turns on")) ((and (member "fan" topic) (member "one" topic) (string-equal "0" payload)) (message "Fan one turns off") (turn-object-off 'fan-one)) ((and (member "fan" topic) (member "two" topic) (string-equal "1" payload)) (message "Fan two turns on") (turn-object-on 'fan-two)) ((and (member "fan" topic) (member "two" topic) (string-equal "0" payload)) (message "Fan two turns off") (turn-object-off 'fan-two)) ((and (member "lamp" topic) (member "one" topic) (string-equal "1" payload)) (message "Lamp one turns on") (turn-object-on 'lamp-one)) ((and (member "lamp" topic) (member "one" topic) (string-equal "0" payload)) (message "Lamp one turns off") (turn-object-off 'lamp-one)) ((and (member "lamp" topic) (member "two" topic) (string-equal "1" payload)) (message "lamp two turns on") (turn-object-on 'lamp-two)) ((and (member "lamp" topic) (member "two" topic) (string-equal "0" payload)) (message "lamp two turns off") (turn-object-off 'lamp-two)) ((and (member "radio" topic) (member "one" topic) (string-equal "1" payload)) (turn-object-on 'radio-one)) ((and (member "radio" topic) (member "one" topic) (string-equal "0" payload)) (turn-object-off 'radio-one)) ((and (member "printer" topic) (member "one" topic) (string-equal "2" payload)) (turn-object-on 'printer-one)) ((and (member "printer" topic) (member "one" topic) (string-equal "1" payload)) (turn-object-on 'printer-one)) ((and (member "printer" topic) (member "one" topic) (string-equal "0" payload)) (turn-object-off 'printer-one)) ((and (member "printer" topic) (member "two" topic) (string-equal "2" payload)) (turn-object-on 'printer-two)) ((and (member "printer" topic) (member "two" topic) (string-equal "1" payload)) (turn-object-on 'printer-two)) ((and (member "printer" topic) (member "two" topic) (string-equal "0" payload)) (turn-object-off 'printer-two))))) ;; printers (add-to-list 'mqtt-message-receive-functions (lambda (msg) "Functions to execute on recieving a message" nil (let ((m (string-split msg " "))) (let ((msg-car (car m)) (payload (cdr m))) (let ((topic (string-split msg-car "/"))) ;; (message "Topic: %s. Payload %s" topic payload) (cond ((member "transform" topic) (illuminate-edges topic (car payload))) ((and (member "main" topic) (member "gesture" topic)) (illuminate-gesture topic (car payload))) ((member "main" topic) (illuminate-nodes topic (car payload))) )))))) (format-graph) (mqtt-start-consumer)