You will need:
- an API key from your account on https://remocon.tv, going forward <api_key> is to be replaced with your API key. You get an API key right away by creating a robot in your account page.
Video Streaming
Video can be streamed to the service using ffmpeg to our https://stream.remocon.tv server
ffmpeg -f v4l2 -framerate 25 -video_size 640x480 -i /dev/video0 \
-f mpegts -codec:v mpeg1video -s 640x480 -b:v 1000k -bf 0 \
https://stream.remocon.tv/<api_key>
API Overview
Our API runs through websockets and returns JSON data.
It works just like any other HTTPS API out there that you are used to, except instead of making HTTPS requests you make a websocket connection, and then interpret the JSON data that you get back.
Interpreting the JSON data is very easy as you will see examples.
This means that it's very simple to set up, to use, and it's compatible with basically everything.
In Python, and MicroPython should be similar:
# run with python3, not with python
import websockets # for web sockets
import asyncio
import json
apiKey = "<api_key>"
domain = "ws://control.remocon.tv/"
async def connectSocket():
url = domain + apiKey
async with websockets.connect(url) as websocket:
print('websocket connected to ' + url)
while True:
input = await websocket.recv()
try:
interpretData(input)
except:
pass
def interpretData(message):
#print(message)
data = json.loads(message)
if (data["type"] == 'keydown' and data["key"] == 87):
print('W key pressed')
# put your code here on what you want to do
# for example you could enable a GPIO pin here
# GPIO.output(17,GPIO.HIGH)
elif (data["type"] == 'keyup' and data["key"] == 87):
print('W key released')
# put your code here on what you want to do
# for example you could disable a GPIO pin here
# GPIO.output(17,GPIO.LOW)
elif (data["type"] == 'keydown' and data["key"] == 83):
print('S key pressed')
# put your code here on what you want to do
elif (data["type"] == 'keyup' and data["key"] == 83):
print('S key released')
# put your code here on what you want to do
# run loop
try:
while True:
asyncio.get_event_loop().run_until_complete(connectSocket())
asyncio.get_event_loop().run_forever()
except KeyboardInterrupt:
pass
except:
pass
In vanilla JavaScript:
In Node.js:
// Install Websockets with
// npm install --save ws
const WebSocket = require('ws');
const socket = new WebSocket('ws://control.remocon.tv/<api_key>'); // Replace this with your API key!
socket.on('open', () => {
console.log('Connected to the WebSocket server');
});
socket.on('message', data => {
const jsonData = JSON.parse(data);
if (jsonData.type === 'keydown' && jsonData.key === 87) {
console.log('W key pressed');
// Put your code here on what you want to do
} else if (jsonData.type === 'keyup' && jsonData.key === 87) {
console.log('W key released');
// Put your code here on what you want to do
} else if (jsonData.type === 'keydown' && jsonData.key === 65) {
console.log('A key pressed');
// Put your code here on what you want to do
} else if (jsonData.type === 'keyup' && jsonData.key === 65) {
console.log('A key released');
// Put your code here on what you want to do
} else if (jsonData.type === 'keydown' && jsonData.key === 83) {
console.log('S key pressed');
// Put your code here on what you want to do
} else if (jsonData.type === 'keyup' && jsonData.key === 83) {
console.log('S key released');
// Put your code here on what you want to do
} else if (jsonData.type === 'keydown' && jsonData.key === 68) {
console.log('D key pressed');
// Put your code here on what you want to do
} else if (jsonData.type === 'keyup' && jsonData.key === 68) {
console.log('D key released');
// Put your code here on what you want to do
}
console.log('Received data:', jsonData);
});
socket.on('close', () => {
console.log('Disconnected from the WebSocket server');
});
socket.on('error', (error) => {
console.error('WebSocket error:', error);
});
setInterval(function () {socket.send('Keep-Alive')}, 1000);
In C and in Arduino:
That's it now get working.
Raspberry Pi Example
Open two terminal windows in your raspberry pi, run the following in each of them. The first streams the video, the second gets the commands from the website to control the motor and steering for a remote control car. To control anything else you just change the commands there.
First terminal window:
ffmpeg -f v4l2 -framerate 25 -video_size 640x480 -i /dev/video0 \
-f mpegts -codec:v mpeg1video -s 640x480 -b:v 1000k -bf 0 \
https://stream.remocon.tv/<api_key>
If that throws an error then try "sudo apt-get install ffmpeg" first, or reach out to us.
Second terminal window:
First create a file called websockets.py and copy this into it:
import RPi.GPIO as GPIO # for raspberry pi GPIO
import websockets # for web sockets
import asyncio
import json # https://www.w3schools.com/python/python_json.asp
# sending data in json format lets us send as much data
# as we want and in any order
apiKey = "<api_key>"
domain = "ws://control.remocon.tv/"
# set GPIO pin variables
# the standard Raspberry Pi 4 pins are: 17, 27, 22, 5, 6, 13, 26, 23, 24, 25, 12, 16
motor = 17
servo = 27
# raspberry pi GPIO setup
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(motor,GPIO.OUT)
GPIO.setup(servo,GPIO.OUT)
motorPWM = GPIO.PWM(motor, 50) # servo GPIO for PWM with 50Hz # <-- might have to
# play around with the frequency for the motor,
# for the servo 50 should work but for the motor I am not sure
motorPWM.start(0)
servoPWM = GPIO.PWM(servo, 50) # servo GPIO for PWM with 50Hz
servoPWM.start(7.5)
async def connectSocket():
url = domain+apiKey
async with websockets.connect(url) as websocket:
print('websocket connected to ' + url)
while True:
input = await websocket.recv()
try:
interpretData(input)
except:
pass
def interpretData(message):
print(message) # comment this out if you don't want to see every single message
data = json.loads(message)
if (data["type"] == 'keydown' and data["key"] == 87):
print('forward key pressed')
motorPWM.ChangeDutyCycle(8)
elif (data["type"] == 'keyup' and data["key"] == 87):
print('forward key released')
motorPWM.ChangeDutyCycle(0)
elif (data["type"] == 'keydown' and data["key"] == 83):
print('backward key pressed')
motorPWM.ChangeDutyCycle(0) # <-- not sure if there
# is a PWM duty cycle for reverse, motors
# should have it but I am not sure what it is
elif (data["type"] == 'keyup' and data["key"] == 83):
print('backward key released')
motorPWM.ChangeDutyCycle(0)
elif (data["type"] == 'keydown' and data["key"] == 65):
print('left key pressed')
servoPWM.ChangeDutyCycle(2.5)
elif (data["type"] == 'keyup' and data["key"] == 65):
print('left key released')
servoPWM.ChangeDutyCycle(7.5)
elif (data["type"] == 'keydown' and data["key"] == 68):
print('right key pressed')
servoPWM.ChangeDutyCycle(12.5)
elif (data["type"] == 'keyup' and data["key"] == 68):
print('right key released')
servoPWM.ChangeDutyCycle(7.5)
asyncio.get_event_loop().run_until_complete(connectSocket())
asyncio.get_event_loop().run_forever()
Then run this in the terminal window:
sudo apt-get install python3
sudo apt-get install python3-pip
pip3 install websockets
pip3 install RPi
python3 websockets.py # <-- this is the file we just created
And you're done, it should work. If you want to have these two run on startup then add them to the crontab file as cron jobs. The benefit of doing it this way is that you can see how it works and then customize what your Raspberry Pi does in response. When you run the websockets file it will show you every command, you can then change what's in the 'if' statements to make the Raspberry Pi do whatever you want.
How to make it run automatically on startup
Still writing this part, although you can do it with cron jobs. This is regarding the Raspberry Pi example above.
crontab -e
Why is this on Neocities rather than on some other documentation site?
It's because it's very easy to use and FOSS and ideologically good.
Last edited on 2023-06-25