beginners

Melody 2025-06-02T16:31:21.781289Z

Can someone help me understand what I am doing wrong in electric clojure? This is a lot of code but I don't know how else to ask this question. @dustingetz To save space here I will put working code for comparison on a reply to this comment I follow this pattern to try and match live data streaming from a device:

(e/defn StartStreamingWhenMatching []
  (e/client
   (let [state (e/watch pong-state/state)
         connected? (get-in state [:bci :device-connected?])
         matching? (get-in state [:bci :matching?])
         streaming? (get-in state [:bci :streaming?])]
     ;; Start streaming when we start matching (if not already streaming)
     (when (and connected? matching? (not streaming?))
       (js/console.log "Starting EEG streaming for brain activity matching")
       (let [stream-result (e/server (bci/start-eeg-streaming-server "pong"))]
         (js/console.log "Stream start result:" (clj->js stream-result))
         (when (:success stream-result)
           (swap! pong-state/state assoc-in [:bci :streaming?] true)))))))

(e/defn PollBrainActivityWhenMatching []
  (e/client
   (let [state (e/watch pong-state/state)
         connected? (get-in state [:bci :device-connected?])
         matching? (get-in state [:bci :matching?])
         streaming? (get-in state [:bci :streaming?])]
     ; Poll when connected, matching, and streaming
     (when (and connected? matching? streaming?)
       ; Should execute whenever the state changes
       (let [confidence-data (e/server (bci/match-brain-activity-server))]
         (js/console.log "Brain activity confidence:" (clj->js confidence-data))
         (when confidence-data
           (swap! pong-state/state assoc-in [:bci :confidence] confidence-data)))))))

and then I am trying to extend the same 'BrainControls'


(e/defn BrainControls []
  (e/client
   (let [state (e/watch pong-state/state)
         connected? (get-in state [:bci :device-connected?])
         pending-connect? (get-in state [:bci :pending-connect])
         pending-disconnect? (get-in state [:bci :pending-disconnect])
         active-profile (get-in state [:bci :active-profile])
         connection-error (get-in state [:bci :connection-error])
         matching? (get-in state [:bci :matching?])
         streaming? (get-in state [:bci :streaming?])
         confidence (get-in state [:bci :confidence])]

     (ConnectWhenPending)
     (DisconnectWhenPending)
     (StartStreamingWhenMatching)
     (StopStreamingWhenNotMatching)
     (PollBrainActivityWhenMatching)

...the rest of the code is the same...
      ; Brain matching toggle (only show when connected)
      (when connected?
        (dom/button
         (dom/props {:class (str "bci-button " (if matching? "stop-matching" "start-matching"))})
         (dom/text (if matching? "Stop Brain Control" "Start Brain Control"))
         (dom/On "click"
                 (fn [_]
                   (swap! pong-state/state assoc-in [:bci :matching?] (not matching?)))
                 nil)))

      ; Show active profile info
      (when (and connected? active-profile)
        (dom/div
         (dom/props {:class "profile-info"})
         (dom/text (str "Profile: " active-profile))
         (when streaming?
           (dom/span
            (dom/props {:class "streaming-indicator"})
            (dom/text " • Streaming")))))

      ; Show brain activity confidence when matching
      (when (and connected? matching? confidence)
        (dom/div
         (dom/props {:class "confidence-display"})
         (dom/div (dom/text (str "Up: " (get confidence :up 0.0))))
         (dom/div (dom/text (str "Down: " (get confidence :down 0.0))))
         (when-let [error (get confidence :error)]
           (dom/div
            (dom/props {:class "confidence-error"})
            (dom/text (str "Error: " error))))))
....)
I keep running into this error and I don't know how to resolve it:
Caused by: clojure.lang.ExceptionInfo:
brain-pong.components/PollBrainActivityWhenMatching:145:40
I cannot resolve [bci/match-brain-activity-server] {:in PollBrainActivityWhenMatching, :for :server}
Can someone help me understand why it can't resolve my function? match-brain-activity-server is a big block of only clojure code:
#?(:clj
   (defn match-brain-activity-server
     []
     (try
       (let [recording? @state/recording?
             eeg-data @state/eeg-data]

         (println "Recording? value:" recording? "type:" (type recording?))
         (println "EEG data value:" (if eeg-data "exists" "nil") "type:" (type eeg-data))
....rest of that function

Melody 2025-06-02T16:33:58.165299Z

The following code works for me to connect to the device I am working with:

(e/defn ConnectWhenPending []
  (e/client
   (let [state (e/watch pong-state/state)]
     (when (get-in state [:bci :pending-connect])
       (js/console.log "Initiating BCI connection!")
       ; Clear the pending state first
       (swap! pong-state/state assoc-in [:bci :pending-connect] false)

       (let [result (e/server (bci/connect-device))]
         (js/console.log "Connection result:" (clj->js result))
         (if (:connected result)
           (do
             (swap! pong-state/state update-in [:bci] merge
                    {:device-connected? (:connected result)
                     :active-profile (:profile-name result)
                     :connection-error nil})
             (js/console.log "Connection successful"))
           (do
             (swap! pong-state/state update-in [:bci] merge
                    {:device-connected? false
                     :active-profile nil
                     :connection-error (:error result)})
             (js/console.log "Connection failed:" (:error result)))))))))

which calls a bunch of server logic in my bci namespace:

#?(:clj
   (defn connect-device []
     (try
       (initialize-modules!)
       (mount/start)
       (println "Server: Connecting to BCI device with active profile")
       (let [active-profile ((:get-active-profile @state/state))
             active-profile-name (:name active-profile)
             connected? (api/connect-from-profile! active-profile)]
         (println "Connection result:" connected?)
         {:connected connected?
          :profile-name active-profile-name})
       (catch Exception e
         (println "Error in connect-device-server:" (.getMessage e))
         {:connected false :error (.getMessage e)}))))
I put that and a similar disconnect function into this BCIControlComponent and I just call this in my main function and it works
(e/defn BrainControls []
  (e/client
   (let [state (e/watch pong-state/state)
         connected? (get-in state [:bci :device-connected?])
         pending-connect? (get-in state [:bci :pending-connect])
         pending-disconnect? (get-in state [:bci :pending-disconnect])
         active-profile (get-in state [:bci :active-profile])
         connection-error (get-in state [:bci :connection-error])]

     (ConnectWhenPending)
     (DisconnectWhenPending)

     (dom/div
      (dom/props {:class "bci-controls"})

      ; Connection button
      (dom/button
       (dom/props {:class (str "bci-button " (if connected? "disconnect" "connect"))
                   :disabled (or pending-connect? pending-disconnect?)})
       (dom/text (cond
                   pending-connect? "Connecting..."
                   pending-disconnect? "Disconnecting..."
                   connected? "Disconnect Device"
                   :else "Connect Device"))
       (dom/On "click"
               (fn [_]
                 (if connected?
                   (swap! pong-state/state assoc-in [:bci :pending-disconnect] true)
                   (swap! pong-state/state assoc-in [:bci :pending-connect] true)))
               nil))

      ; Show active profile info
      (when (and connected? active-profile)
        (dom/div
         (dom/props {:class "profile-info"})
         (dom/text (str "Profile: " active-profile))))

      ; Show connection error if any
      (when connection-error
        (dom/div
         (dom/props {:class "connection-error"})
         (dom/text (str "Error: " connection-error))))))))

seancorfield 2025-06-02T16:42:14.344429Z

Maybe post this in #hyperfiddle instead? That's where the Electric folks hang out (I know, not very discoverable 😞 ) I'd say Electric Clojure questions are inherently not "beginner-level", even when you are a Clojure beginner.

oλv 2025-06-02T16:49:55.530709Z

Hey Lor! I can help you look more into this (as promised @reclojure 😅) at a later hour, but a general help-seeking and debugging advice is to spend some time removing as much code as possible without the problem going away. Then the problem and solution usually reveals itself. If not, the programmer you ask for help will be very happy to receive a minimum viable example (MVE) to debug it quickly on their end.

Melody 2025-06-02T17:08:55.279709Z

@seancorfield Ah I tried to find an electric or hyperfiddle channel but it wasn't showing up in my search bar. I will repost there. @post972 Imk whenever you might be free. I tried several approaches and this seemed like the most minimal I could make it...

seancorfield 2025-06-02T17:09:52.280989Z

No worries. I just suspect you'll get more/better/quicker answers there 🙂

oλv 2025-06-02T17:12:32.561659Z

It helps a lot if the example is runnable for other people. Make a commit others can check out on their machine. I'm free tomorrow June 3 20:00 CEST