API version 0
This will not receive support after versions >=0.2. Use the version 1 API instead.
Adding the built-in routes
To add the built-in routes into your program, you need to use the com_server.api module. This module provides the built-in routes for all supported versions of the API. For example, to use version 0 of the API, you can simply import the V0 class from the com_server.api module and wrap it around the RestApiHandler object. When the server is launched, this will add all routes from version 0, prefixed with /v0.
from com_server import Connection, RestApiHandler
from com_server.api import V0
conn = Connection(<baud>, "<port>")
handler = RestApiHandler(conn)
V0(handler) # adds built-in endpoints from version 0
handler.run(host="0.0.0.0", port=8080)
Note that adding built-in routes means that those routes cannot be added again later. If they are, it will raise com_server.EndpointExistsException.
Endpoints from RestApiHandler
These endpoints cannot be used in any case with the RestApiHandler, even if has_register_recall is False. If they are defined again by the user, it will raise com_server.EndpointExistsException.
These endpoints will not apply if has_register_recall is False, and the response will be a 404 Not Found.
If an endpoint is reached while another process is using another endpoint, then the endpoint will respond with 503 Service Unavailable.
/register
Registers an IP to the server. Note that this is IP-based, not process based, so if there are multiple process on the same computer connecting to this, the server will not be able to detect it and may lead to unexpected behavior.
Method: GET
Arguments: None
Response:
200 OK:{"message": "OK"}if successful400 Bad Request:{"message": "Double registration"}if this endpoint is reached by an IP while it is registered{"message": "Not registered; only one connection at a time"}if this endpoint is reached while another IP is registered
503 Service Unavailable:{"message": "An endpoint is currently in use by another process."}if this endpoint was reached while another endpoint is in use.
/recall
Unregisters an IP from a server and allows other IPs to use it.
Method: GET
Arguments: None
Response:
200 OK:{"message": "OK}if successful400 Bad Request:{"message": "Nothing has been registered"}if try to call without any IP registered{"message": "Not same user as one in session"}if called with different IP as the one registered
503 Service Unavailable:{"message": "An endpoint is currently in use by another process."}if this endpoint was reached while another endpoint is in use.
What happens if the serial device disconnects?
When the server is started, there will be a thread checking the connection state of the serial device every 0.01 seconds, and if it disconnects, the thread will attempt to reconnect the device.
Any request made to any endpoint the requires use of the serial port will have a response of 500 Internal Server Error when the device is disconnected and will behave normally once reconnected.
Notes:
- When it reconnects, it calls the
reconnect()method in theConnectionobject. It will try to reconnect to the ports given in__init__(), which means that if the port was changed somehow between disconnecting and reconnecting, it will not reconnect and will require restarting the server. - Disconnect and reconnect events will be logged to
stdoutfor both development and production servers. You can specify a file to log these events to in thelogfileparameter when callingRestApiHandler.run()orRestApiHandler.run_dev(). The time, logging level (INFO and WARNING), and disconnect and reconnect messages will be logged to the file. - Disconnecting the serial device will reset the receive and send queues.
All endpoints below will be prefixed with /v0. For example, to access /send on localhost:8080, you would need to visit localhost:8080/v0/send.
Version-specific arguments
Some version-specific arguments for version 0 can be passed when initializing the V0 or Builtins class from com_server.api. These include:
verbose: Prints the arguments each endpoint receives to stdout. Should not be used in production. By default False.
Endpoints from Builtins
/send
Endpoint to send data to the serial port.
Calls Connection.send() with given arguments in request.
Method: POST
Arguments:
- "data" (str, list): The data to send; can be provided in multiple arguments, which will be concatenated with the
concatenatevariable. - "ending" (str) (optional): A character or string that will be appended to
dataafter being concatenated before sending to the serial port. By default a carraige return + newline. - "concatenate" (str) (optional): The character or string that elements of "data" should be concatenated by if its size is greater than 1; won't affect "data" if the size of the list is equal to 1. By default a space.
Response:
200 OK:{"message": "OK"}if send through
502 Bad Gateway:{"message": "Failed to send"}if something went wrong with sending (i.e.Connection.send()returned false)
400 Bad Request:{"message": "Not registered; only one connection at a time"}ifhas_register_recallis True and the user has not registered by going to the /register endpoint
503 Service Unavailable:{"message": "An endpoint is currently in use by another process."}if this endpoint was reached while another endpoint is in use.
/receive
Endpoint to get data that was recently received.
If POST, calls Connection.receive_str(...) with arguments given in request.
If GET, calls Connection.receive_str(...) with default arguments (except strip=True). This means
that it responds with the latest received string with everything included after
being stripped of whitespaces and newlines.
Method: GET, POST
Arguments (POST only):
- "num_before" (int) (optional): How recent the receive object should be. If 0, then returns most recent received object. If 1, then returns the second most recent received object, etc. By default 0.
- "read_until" (str, null) (optional): Will return a string that terminates with
character in "read_until", excluding that character or string. For example,
if the bytes was
b'123456'and "read_until" was 6, then it will return'12345'. If ommitted, then returns the entire string. By default returns entire string. - "strip" (bool) (optional): If true, then strips received and processed string of whitespaces and newlines and responds with result. Otherwise, returns raw string. Note that using {"strip": False} may not work; it is better to omit it. By default False.
Response:
200 OK:{"message": "OK", "timestamp": ..., "data": "..."}where "timestamp" (float, null) is the Unix epoch time that the message was received and "data" (string, null) is the data that was processed. If nothing was received, then "data" and "timestamp" would be None/null.
400 Bad Request:{"message": "Not registered; only one connection at a time"}ifhas_register_recallis True and the user has not registered by going to the /register endpoint
503 Service Unavailable:{"message": "An endpoint is currently in use by another process."}if this endpoint was reached while another endpoint is in use.
/receive/all
Returns the entire receive queue. Calls Connection.get_all_rcv_str(...).
If POST then uses arguments in request.
If GET then uses default arguments (except strip=True), which means that
that it responds with the latest received string with everything included after
being stripped of whitespaces and newlines.
Method: GET, POST
Arguments (POST only):
- "read_until" (str, null) (optional): Will return a string that terminates with
character in "read_until", excluding that character or string. For example,
if the bytes was
b'123456'and "read_until" was 6, then it will return'12345'. If ommitted, then returns the entire string. By default returns entire string. - "strip" (bool) (optional): If true, then strips received and processed string of whitespaces and newlines and responds with result. Otherwise, returns raw string. Note that using {"strip": False} may not work; it is better to omit it. By default False.
Response:
200 OK:{"message": "OK", "timestamps": [...], "data": [...]}: where "timestamps" (list[float]) contains the list of timestamps in the receive queue and "data" (list[string]) contains the list of data in the receive queue. The indices for "timestamps" and "data" match.
400 Bad Request:{"message": "Not registered; only one connection at a time"}ifhas_register_recallis True and the user has not registered by going to the /register endpoint
503 Service Unavailable:{"message": "An endpoint is currently in use by another process."}if this endpoint was reached while another endpoint is in use.
/get
Waits for the first string from the serial port after request.
If no string after timeout (specified on server side), then responds with 502.
Calls Connection.get(str, ...).
If POST then uses arguments in request.
If GET then uses default arguments (except strip=True), which means that
that it responds with the latest received string with everything included after
being stripped of whitespaces and newlines.
Method: GET, POST
Arguments (POST only):
- "read_until" (str, null) (optional): Will return a string that terminates with
character in "read_until", excluding that character or string. For example,
if the bytes was
b'123456'and "read_until" was 6, then it will return'12345'. If ommitted, then returns the entire string. By default returns entire string. - "strip" (bool) (optional): If true, then strips received and processed string of whitespaces and newlines and responds with result. Otherwise, returns raw string. Note that using {"strip": False} may not work; it is better to omit it. By default False.
Response:
200 OK:{"message": "OK", "data": "..."}where "data" (string) is received data
502 Bad Gateway:{"message": "Nothing received"}if nothing was received from the serial port within the timeout specified on the server side.
400 Bad Request:{"message": "Not registered; only one connection at a time"}ifhas_register_recallis True and the user has not registered by going to the /register endpoint
503 Service Unavailable:{"message": "An endpoint is currently in use by another process."}if this endpoint was reached while another endpoint is in use.
/send/get_first
Respond with the first string received from the
serial port after sending something given in request.
Calls Connection.get_first_response(is_bytes=False, ...).
Method: POST
Arguments:
- "data" (str, list): Everything that is to be sent, each as a separate parameter. Must have at least one parameter.
- "ending" (str) (optional): The ending of the bytes object to be sent through the Serial port. By default a carraige return ("\r\n")
- "concatenate" (str) (optional): What the strings in args should be concatenated by
- "read_until" (str, None) (optional): Will return a string that terminates with
read_until, excludingread_until. For example, if the string was"abcdefg123456\n", andread_untilwas\n, then it will return"abcdefg123456". Ifread_untilis None, the it will return the entire string. By default None. - "strip" (bool) (optional): If true, then strips received and processed string of whitespaces and newlines and responds with result. Otherwise, returns raw string. Note that using {"strip": False} may not work; it is better to omit it. By default False.
Response:
200 OK:{"message": "OK", "data": "..."}where "data" (string) is the data that was processed.
502 Bad Gateway:{"message": "Nothing received"}if nothing was received from the serial port within the timeout specified on the server side.
400 Bad Request:{"message": "Not registered; only one connection at a time"}ifhas_register_recallis True and the user has not registered by going to the /register endpoint
503 Service Unavailable:{"message": "An endpoint is currently in use by another process."}if this endpoint was reached while another endpoint is in use.
/get/wait
Waits until connection receives string data given in request.
Calls Connection.wait_for_response(...).
Method: POST
Arguments:
- "response" (str): The string the program is waiting to receive.
Compares to response to
Connection.receive_str(). - "read_until" (str, None) (optional): Will return a string that terminates with
read_until, excludingread_until. For example, if the string was"abcdefg123456\n", andread_untilwas\n, then it will return"abcdefg123456". Ifread_untilis None, the it will return the entire string. By default None. - "strip" (bool) (optional): If true, then strips received and processed string of whitespaces and newlines and responds with result. Otherwise, returns raw string. Note that using {"strip": False} may not work; it is better to omit it. By default False.
Response:
200 OK:{"message": "OK"}if everything was able to send through
502 Bad Gateway:{"message": "Nothing received"}if nothing was received from the serial port within the timeout specified on the server side.
400 Bad Request:{"message": "Not registered; only one connection at a time"}ifhas_register_recallis True and the user has not registered by going to the /register endpoint
503 Service Unavailable:{"message": "An endpoint is currently in use by another process."}if this endpoint was reached while another endpoint is in use.
/send/get
Continues sending something until connection receives data given in request.
Calls Connection.send_for_response(...)
Method: POST
Arguments:
- "response" (str): The string the program is waiting to receive.
Compares to response to
Connection.receive_str(). - "data" (str, list): Everything that is to be sent, each as a separate parameter. Must have at least one parameter.
- "ending" (str) (optional): The ending of the bytes object to be sent through the Serial port. By default a carraige return ("\r\n")
- "concatenate" (str) (optional): What the strings in args should be concatenated by
- "read_until" (str, None) (optional): Will return a string that terminates with
read_until, excludingread_until. For example, if the string was"abcdefg123456\n", andread_untilwas\n, then it will return"abcdefg123456". Ifread_untilis None, the it will return the entire string. By default None. - "strip" (bool) (optional): If true, then strips received and processed string of whitespaces and newlines and responds with result. Otherwise, returns raw string. Note that using {"strip": False} may not work; it is better to omit it. By default False.
Response:
200 OK:{"message": "OK"}if everything was able to send through
502 Bad Gateway:{"message": "Nothing received"}if nothing was received from the serial port within the timeout specified on the server side.
400 Bad Request:{"message": "Not registered; only one connection at a time"}ifhas_register_recallis True and the user has not registered by going to the /register endpoint
503 Service Unavailable:{"message": "An endpoint is currently in use by another process."}if this endpoint was reached while another endpoint is in use.
/connection_state
Responds with an object of the properties of the connection state.
timeout(float): The timeout of the object, or how much time it will try doing something, such as sending data, before breaking out of the programsend_interval(float): The time the program will wait before allowing something to be sent to the serial port againavailable(int): The number of new data available since the last time data was received by the user.port(str): The serial port it is connected to
Method: GET
Arguments: None
Response:
200 OK:{"message": "OK", "state": {...}}: where "state" represents an object with items above
400 Bad Request:{"message": "Not registered; only one connection at a time"}ifhas_register_recallis True and the user has not registered by going to the /register endpoint
503 Service Unavailable:{"message": "An endpoint is currently in use by another process."}if this endpoint was reached while another endpoint is in use.
/connected
Indicates if the serial port is currently connected or not.
Returns the Connection.connected property.
Method: GET
Arguments: None
Response:
200 OK:{"message": "OK", "connected": ...}: where "connected" (bool) is the connected state:trueif connected,falseif not.
400 Bad Request:{"message": "Not registered; only one connection at a time"}ifhas_register_recallis True and the user has not registered by going to the /register endpoint
503 Service Unavailable:{"message": "An endpoint is currently in use by another process."}if this endpoint was reached while another endpoint is in use.
/list_ports
Lists all available Serial ports. Calls com_server.tools.all_ports()
and returns list of lists of size 3: [port, description, technical description]
Method: GET
Arguments: None
Response:
200 OK:{"message": "OK", "ports": [["...", "...", "..."], "..."]}where "ports" (list[list[string]]) is a list of lists of size 3, each one indicating the port, description, and technical description
400 Bad Request:{"message": "Not registered; only one connection at a time"}ifhas_register_recallis True and the user has not registered by going to the /register endpoint
503 Service Unavailable:{"message": "An endpoint is currently in use by another process."}if this endpoint was reached while another endpoint is in use.
Escape characters
When including escape characters (newlines, carriage returns, etc.) in a post request to one of the endpoints, the request might not interpret the character. For example, in some cases, if you send ending="\n" to the /send endpoint (other endpoints have this issue too; we're just using /send as an example), the server may interpret it as "\\n" (a backslash followed by n), rather than an actual newline. Below contains a list of ways to solve this for different programs:
Python requests library
The Python requests library works by default if you put a normal newline character \n (or any other escape character) in the string.
cURL
If you are using zsh or bash, then you can use the $'' syntax to include escape characters. For example, sending data to /send with cURL can look like:
$ curl -X POST -d "data=hello" -d $'ending=\n' <url>
JSON
Escape characters should work normally with JSON.
Adding more programs
If you want to add more programs to this list, feel free to submit a pull request. If something does not work or you see something wrong, please submit an issue under the category "Documentation."