CSEED speakers control

Dear All,
I have been asked to control some CSEED ( www.cseed.tv ) speakers through POST HTTP Json commands. The protocol says:

CSeed Speaker - JSON HTTP API

Request data is sent via HTTP POST to http://SPEAKER_IP:8314/api

request: {"action":"XXX","data":{...}}
response: {"data":{}} or {"errorCode":XXX,"errorText":"XXX"}

****Motor Control****
Up
action: "motorUp"

********Examples********
Motor Up: {"action":"motorUp","data":{“dummy”:true}}

****Knowledge Base****
If an empty JSON object is needed, please send it via: “object:{“dummy”:true}” instead of “object:{}”

It does not have a web interface to give me the chance to control it through a web browser and see the post command syntax so I cannot make it work.
Can you please help me somehow regarding to the POST command syntax ?

George

Comments

  • HARMAN_icraigieHARMAN_icraigie Technical Trainer II, Harman Professional University Posts: 426

    Try sending this from a web browser.

    http://SPEAKER_IP:8314/{"action":"motorUp","data":{“dummy”:true}}

    Also Wire Shark is you friend when developing code for this sort of communications

  • George KrietsepisGeorge Krietsepis Junior Member Posts: 155

    Hello Ian,
    this is the obvious command that should be sent through the browser but it doesn't work.
    Wire Shark will be my friend once a command has been successfully sent through the browser. For the moment, I have not managed it.
    Any other ideas please ?

    George

  • HARMAN_icraigieHARMAN_icraigie Technical Trainer II, Harman Professional University Posts: 426

    Oops, missed the POST method reference

    Try Postman

    https://toolsqa.com/postman/post-request-in-postman/

  • sentry07sentry07 Junior Member Posts: 39
    edited March 14

    So a POST header looks like a GET header except you need to specify the content type and content length and your data follows the header. There are always two CRLFs($0D,$0A) between the header and the data and then two CRLFs after the data. It would look like this:

    POST /api HTTP/1.1 CRLF
    HOST: speaker.ip.address CRLF
    Connection: Close CRLF
    Content-Type: application/json CRLF
    Content-Length: integer length of your JSON data CRLF
    CRLF
    {"action":"motorUp","data":{“dummy”:true}} CRLF
    CRLF

    You connect to the speaker IP address on port 8314 and send all that either in one string or subsequent strings. LENGTH_STRING the JSON data (not including the CRLFs) and put it in the Content-Length field.

  • George KrietsepisGeorge Krietsepis Junior Member Posts: 155

    on this case json data is the length of the {"action":"motorUp","data":{“dummy”:true}} string ? Which means 42 ?
    As per your suggestion:

    button_event[vdvVirtual,1]
    {
    push :
    {
    send_string dvSpeaker2, "'POST /api HTTP/1.1', 13,10"
    send_string dvSpeaker2, "'HOST: 10.100.60.100',13,10"
    send_string dvSpeaker2, "'Connection: Close',13,10"
    send_string dvSpeaker2, "'Content-type: application/json',13,10"
    send_string dvSpeaker2, "'Content-Length: 42',13,10"
    send_string dvSpeaker2, "13,10"
    send_string dvSpeaker2, "'{"action":"motorUp","data":{“dummy”:true}}',13,10"
    send_string dvSpeaker2, "13,10"
    }
    }

    And the response:

    Line 7 2019-03-14 (21:59:42):: String recieved from Speaker2: HTTP/1.1 500 Internal Error$0D$0AContent-Length: 0$0D$0A$0D$0A$0A

    Should the Connection be "Close" or "keep-alive" ?

  • sentry07sentry07 Junior Member Posts: 39

    I always use Close personally so that the OFFLINE event signals the end of communication and I can parse what came back in the buffer. If you use keep-alive, then you have to decide when to start parsing data based on what you've received.

    I tried this out in Python, generating a post request to myself and I got this:
    POST /api HTTP/1.1
    Host: localhost
    User-Agent: python-requests/2.9.2
    Accept-Encoding: gzip, deflate
    Accept: /
    Connection: keep-alive
    Content-Length: 52
    Content-Type: application/json

    "{\"action\":\"motorUp\",\"data\":{\"dummy\":true}}"

    So it looks like you have to enclose the JSON data in quotes, and escape any quotes inside the string, and all of that contributes to Content-Length.

  • viningvining X Member Posts: 4,323

    If I recall when doing things like this it’s better to concantenate the entire string and do a single send_string to the device.

  • Duncan EllisDuncan Ellis Code Junkie Posts: 89

    I got these to work, it took a bit of experimentation. this is copied directly out of my code. there may be a few defunkt thing still in as it was very last minute and client was due to land. but it works!

    You have to send these commands to each speaker. There is an array needed with the IP addresses of the speaker controllers sCSeedIP[][15]

    In our case there were a stereo pair and a sub.

    Hope you get it sorted

    DEFINE_CALL 'CONSTRUCT SPEAKER COMMANDS' (INTEGER nIndex, INTEGER nCmd)
    {
    LOCAL_VAR CHAR sHTTPheader [2000]
    LOCAL_VAR CHAR sHTTPBody [1000]

    LOCAL_VAR CHAR s64[200]
    LOCAL_VAR INTEGER nCmdRef
    LOCAL_VAR INTEGER nCmdType

    nIntercomCurrentCommand = nCmd

    SELECT
    {
    ACTIVE(nCmd = SPEAKERS_UP):
    {
    sSpeakerURI = "'/api'"
    sHTTPBody = "'{"action":"motorUp","data":{"dummy":true}}',$0D,$0A,$0D,$0A"
    }
    ACTIVE(nCmd = SPEAKERS_DN):
    {
    sSpeakerURI = "'/api'"
    sHTTPBody = "'{"action":"motorDown","data":{"dummy":true}}',$0D,$0A,$0D,$0A"
    }
    ACTIVE(nCmd = SPEAKERS_STOP):
    {
    sSpeakerURI = "'/api'"
    sHTTPBody = "'{"action":"motorStop","data":{"dummy":true}}',$0D,$0A,$0D,$0A"
    }
    }

    sHTTPheader= "'POST ',sSpeakerURI,' HTTP/1.1',$0D,$0A,
              'HOST: ',sCSeedIP[nIndex],':8314',$0D,$0A,
              'USER-AGENT: Integrated System Control Ltd 14/08/18',$0D,$0A,
              'ACCEPT-LANGUAGE: EN',$0D,$0A,
              'CONNECTION:CLOSE',$0D,$0A"
    

    sFinalSpkCmd[nIndex] = "sHTTPheader,'CONTENT-LENGTH:',ITOA(LENGTH_STRING(sHTTPBody)),$0d,$0a,$0D,$0A,sHTTPBody"

    IP_CLIENT_OPEN(dvCSEED[nIndex].Port,sCSeedIP[nIndex],8314,IP_TCP)
    }

  • George KrietsepisGeorge Krietsepis Junior Member Posts: 155

    Thanks you All,

    Finally I made it work writing the below code:

    volatile char moveSpeakerUp[] ='{"action":"motorUp","data":{"forced":true}}'

        send_string dvSpeakerPool1, "'POST /api HTTP/1.1', 13,10"
    send_string dvSpeakerPool1, "'Host: 10.100.60.100',13,10"
    send_string dvSpeakerPool1, "'Content-type: application/json',13,10"
    send_string dvSpeakerPool1, "'Content-Length: ',itoa(length_string(moveSpeakerUp)),13,10"
        send_string dvSpeakerPool1, "'Connection: keep-alive',13,10"
    send_string dvSpeakerPool1, "13,10"
    send_string dvSpeakerPool1, "'{"action":"motorUp","data":{"forced":true}}',13,10"
    

    Duncan,
    do you have any kind of feedback, like speaker is moving or speaker has reached upper limit, etc.
    I always have a feedback - after a successful command - like {"data":{}} which means nothing for me

    George

  • Duncan EllisDuncan Ellis Code Junkie Posts: 89

    Hi George

    I never had chance to even look at it . I got asked to do this at very last minute and we have never had chance to go back and have a look at it. I wanted to but I had to figure this out in about 2 hours and this is as far as I got. It worked and then we were being ushered out

  • Duncan EllisDuncan Ellis Code Junkie Posts: 89

    Although, I seem to remember that you have to be careful when using 'Forced' in your command. I seem to remember that it overrides one of the safety features....Can't fully remember though. would recommend you read the document fully

Sign In or Register to comment.