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
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
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
Oops, missed the POST method reference
Try Postman
https://toolsqa.com/postman/post-request-in-postman/
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.
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" ?
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.
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.
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"
}
}
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)
}
Thanks you All,
Finally I made it work writing the below code:
volatile char moveSpeakerUp[] ='{"action":"motorUp","data":{"forced":true}}'
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
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
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