dnadoba / sACN

sACN (E1.31) protocol implementation in Swift to send DMX Data over UDP using Network.framework
13 stars 4 forks source link

Sent data does not work / it doesnt send #2

Open simpelMIC opened 9 months ago

simpelMIC commented 9 months ago

Hi, I have a problem using this package. I'm building a macOS application using Swiftui and I'm not able to control my lights with this package. I have a Raspberry Pi set up with OLA. To explain the problem a bit further, yesterday I set up the Raspberry Pi. I checked the XCode Network (Debug) Monitor to look for Network Traffic, and indeed, I saw data was going out of my program into the pi. (Yes I checked the pi too). But no values seemed to change in the universe. I retried multiple times and tried different methods too. My current attempt is using UDP Unicast to a local IP address. (Yes I tried plugging every component into a switch, and yes it didn't work) I checked every reachability, and to my surprise when I used qlc+ everything worked out fine. So it seems the problem is on the side of this package. I hope to get some help or answer on this issue because the other one didn't really get any response. Best regards, MIC

let connection = Connection(endpoint: .hostPort(host: "192.168.178.178", port: .sACN), universe: 1)
connection.sendDMXData(Data([255, 0, 0, 0, 255]), priority: 200, isPreviewData: false)

In OLA:

Bildschirmfoto 2024-02-24 um 21 50 18 Bildschirmfoto 2024-02-24 um 21 50 30 Bildschirmfoto 2024-02-24 um 21 51 11

IN XCode:

Bildschirmfoto 2024-02-24 um 23 35 09
dnadoba commented 9 months ago

My best guess is that you haven't the right entitlements setup for your macOS app which by default enables sandboxing. You will need the com.apple.security.network.client and com.apple.security.network.server entitlements for UDP connections.

This can be setup in the Xcode UI. Select your Xcode Project file, then your target and go to the Signing & Capabilities tab. Under "App Sandbox" select both checkboxes under Networking, Incoming Connections (Server) and Outgoing Connections (Client).

simpelMIC commented 9 months ago

Hi dnadoba, I have already made this change to my XCode Project. It still does not work. :) Best regards, MIC

Bildschirmfoto 2024-02-27 um 22 24 00
dnadoba commented 9 months ago

Hm okay. I have only ever used it with UDP broadcast. Maybe try this. Another thing I would try is setting the connection.connection.stateUpdateHandler to a closure that prints the state. In addition, instead of using connection.send(..., completion: .idempotent) in sendDMXData(...) you could change that to take a closure as well and print the error, if any is present. You will need to change that in this package though. Just clone it and drag & drop it into your Xcode project to edit it. This should give you a better idea what's going on. I can also recommend using Wireshark to see if any packets are send out.

simpelMIC commented 8 months ago

So this is the class I've set up

class e131sACNController: ObservableObject {
    @Binding var dmxChannels: [DMXChannel]
    @Published var isStreaming = false

    //Settings
    var host: NWEndpoint.Host = "192.168.178.178"
    var port: NWEndpoint.Port = .sACN
    var universe: UInt16

    init(dmxChannels: Binding<[DMXChannel]>, universe: UInt16) {
        self._dmxChannels = dmxChannels
        self.universe = universe
        print("sACN Initialized")
    }

    func sendDMXData() {
        let connection = Connection(endpoint: .hostPort(host: host, port: port), universe: 1)
        connection.sendDMXData(Data([255, 0, 0, 0, 255]), priority: 100, isPreviewData: false)
    }
}

I've already used Wireshark to compare the data packets sent by the sACN Package and QLC+. The packages sent by QLC+ had a size of about 600 bytes while the ones from the package only had a size of around 40. UDP Multicast doesn't work in my case, because the Raspberry Pi doesn't receive the packages sent. If I'm using UDP Unicast (endpoint: .hostPort(host: host, port: port)) the Pi receives the packages but OLA doesn't recognize them. Regards, MIC

dnadoba commented 8 months ago

You need to keep the Connection object alive or otherwise the connection will be cancelled on deinit, in you case at the end of the your sendDMXData function and the UDP message will likely not be send. Consider initialising the Connection in the init and keeping it as a stored property.

40 bytes is definitely wrong, it needs to be a lot more. You can also try adding padding zeros at the end to make the whole DMX data 512 bytes long, maybe the other side always expects 512 bytes of DMX data.

dnadoba commented 8 months ago

Also, please try out the demo and modify it to your needs to see if that works on your setup: https://github.com/dnadoba/sACN/blob/master/Sources/sACNDemo/main.swift

simpelMIC commented 8 months ago

Ok I changed some things in my code and now I think the connection is fine. It monitors perfectly in the XCode Network Monitor and the length is 600 bytes with my normal channel variables.

class e131sACNController: ObservableObject {
    @Binding var dmxChannels: [DMXChannel]
    @Published var isStreaming = false

    var host: NWEndpoint.Host = "192.168.178.178"
    var port: NWEndpoint.Port = .sACN
    var universe: UInt16

    var connection: Connection

    init(dmxChannels: Binding<[DMXChannel]>, universe: UInt16) {
        self._dmxChannels = dmxChannels
        self.universe = universe
        self.connection = Connection(endpoint: .hostPort(host: host, port: port), universe: universe)
        print("sACN Initialized")
    }

    func timer() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 1/20) {
            if self.isStreaming == true {
                self.timer()
                self.sendDMXData()
            }
        }
    }

    func startStreaming() {
        isStreaming = true
        timer()
    }

    func stopStreaming() {
        isStreaming = false
    }

    func sendDMXData() {
        let dmxValues = dmxChannels.map { UInt8($0.value) }
        let dmxData = Data(dmxValues)

        print(dmxValues)

        connection.sendDMXData(Data(dmxData), priority: 100, isPreviewData: false)
    }
}

The Log looks like this:

[255, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

But it's still not working... My lamp didn't light up. QLC+ works btw. So what seems to be the problem? If you have any questions regarding the rest of my project feel free to ask :) But it's also listed on my github.

A DMXChannel looks like this:

struct DMXChannel: Equatable, Identifiable, Codable {
    var id = UUID()
    var value: Double //Value of Channel 0-255
}

and I create 512 of them when a new project is made. Regards, MIC

dnadoba commented 8 months ago

You can try to use the sACNView app and check if the values are correctly received. Use your own IP for testing this. Maybe your Raspberry Pi only accepts the first "connection". Try restarting and sending data first from your app before QLC+. Double check IP and also the Port. Double check the DMX values you send if they map to the fixture you are using.

simpelMIC commented 8 months ago

Ok thanks for the help. It doesn't directly work, but if I pass it through QLC+ it works. I think my OLA didn't accept the signals for some reason. In sACNView it looked good and it worked in QLC+ too. So thanks a lot :) Regards, MIC