Johnathan B - HiCould someone point me in the ...
Hi
Could someone point me in the right direction please as I am now going around in circles.
I'm trying to write some very basic Python code to post a value to a path. I ultimately want to port it to CircuitPython. I have code to get an auth token and post a path value successfully via steaming websockets running in Python, but there are some issue porting this to circuit python. I have therefore been trying to write code in Python (on a PC) using a straightforward PUT , but whatever I try and can not get it to work.
I have separate code to successfully make and access request and return the device token (manually hard coded int his example below) .
In this simple test example below I am returning code 401 "You do not have permission to view this resource, <a href='/admin/#/login'>Please Login</a>"
Having spent most of the day on this trying many approaches I am clearly getting something fundamentally wrong. I would be grateful of any pointers - thank you.
(
import requests
server_url = "http://192.168.2.133:3000"
# Token hard coded from previously authorized access request
api_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkZXZpY2UiOiJ5b3VyX2RldmljZV9pZCIsImlhdCI6MTcxMTQ2Nzg1N30.X2wxz-qzux0RWQyFq8zQ8v1La9jGBf9r1iL0xgjtliE"
path = "electrical/batteries/999/capacity/timeRemaining"
value = 120
# Construct URL with path
url = f"{server_url}/signalk/v1/{path}"
# Set headers with API token
headers = {
"Authorization": f"Bearer {api_token}",
"Content-Type": "application/json",
}
# Data to send in PUT request
data = {"value": value}
try:
# Send PUT request
response = requests.put(url, headers=headers, json=data)
# Check for successful response
if response.status_code == 200:
print("Value written successfully to Signal K path:", path)
else:
print(f"Error writing to Signal K path: {path}. Status code: {response.status_code}")
print(response.text)
except requests.exceptions.RequestException as e:
print(f"Error: {e}")
)9 Replies
Your json data is probably formatted incorrectly. Signalk is probably expecting a delta update. http://signalk.org/2014/11/05/new-delta-format.html
You can test with the data fiddler. http://[server-ip]:3000/admin/#/serverConfiguration/datafiddler
Thanks for your help Roger
I had tried the json previously.
Here is the same code but no using the url /signalk/v1/api and some json that works fine in the data fiddler.
Again I get this errror
Error writing to Signal K path: api/. Status code: 401
You do not have permission to view this resource, <a href='/admin/#/login'>Please Login</a>
Previously I have tried the same code but creating the token based on an u / p login - with the same issue.
(
import requests
# Replace with your Signal K server URL and API token
server_url = "http://192.168.2.133:3000"
api_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkZXZpY2UiOiJ5b3VyX2RldmljZV9pZCIsImlhdCI6MTcxMTQ2Nzg1N30.X2wxz-qzux0RWQyFq8zQ8v1La9jGBf9r1iL0xgjtliE"
# Path to write to
path = "api/" #----------------------Changed here
# Value to write (replace with desired time remaining value)
value = 120 # Example value in minutes
# Construct URL with path
url = f"{server_url}/signalk/v1/{path}"
# Set headers with API token
headers = {
"Authorization": f"Bearer {api_token}",
"Content-Type": "application/json",
}
# Data to send in PUT request
#----------------------Changed here
data = {"updates": [{"values": [{"path": "electrical.batteries.999.capacity.timeRemaining", "value": 1234}]}]}
try:
# Send PUT request
response = requests.put(url, headers=headers, json=data)
# Check for successful response
if response.status_code == 200:
print("Value written successfully to Signal K path:", path)
else:
print(f"Error writing to Signal K path: {path}. Status code: {response.status_code}")
print(response.text)
except requests.exceptions.RequestException as e:
print(f"Error: {e}")
)A 401 error suggests that the token is invalid or expired.
Thanks for taking the time to reply Roger.
Here is is the same code but this time it includes getting a token when first run instead of using and access request. This gives a response of 400, but returns some HTML saying their is a problem with the Json. The output of my code looks like this. If I check the posted json in the datafiddler it validates post fine. {'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImFkbWluIiwiaWF0IjoxNzExNTM4MjU0LCJleHAiOjE3OTc5MzgyNTR9.oo0FWBOFVRbzv-bA0TzEqzyG4ydAPZL5AkfJRmtF37Y', 'Content-Type': 'application/json'} {"updates": [{"values": [{"path": "electrical.batteries.999.capacity.timeRemaining", "value": 1234}]}]} http://192.168.2.133:3000/signalk/v1/api/ Error writing to Signal K path: api/. Status code: 400 html> <head> <meta charset='utf-8'> <title>SyntaxError: Unexpected token " in JSON at position 0</title> ...... more HTML The stakctrace is: <ul id="stacktrace"><li> at JSON.parse (<anonymous>)</li><li> at createStrictSyntaxError (/usr/local/lib/node_modules/signalk-server/node_modules/body-parser/lib/types/json.js:169:10)</li><li> at parse (/usr/local/lib/node_modules/signalk-server/node_modules/body-parser/lib/types/json.js:86:15)</li><li> at /usr/local/lib/node_modules/signalk-server/node_modules/body-parser/lib/read.js:128:18</li><li> at AsyncResource.runInAsyncScope (node:async_hooks:203:9)</li><li> at invokeCallback (/usr/local/lib/node_modules/signalk-server/node_modules/raw-body/index.js:238:16)</li><li> at done (/usr/local/lib/node_modules/signalk-server/node_modules/raw-body/index.js:227:7)</li><li> at IncomingMessage.onEnd (/usr/local/lib/node_modules/signalk-server/node_modules/raw-body/index.js:287:7)</li> The odd thing is I can successfully post the same json using websockets in Python. My test code for the output above is: (
Here is is the same code but this time it includes getting a token when first run instead of using and access request. This gives a response of 400, but returns some HTML saying their is a problem with the Json. The output of my code looks like this. If I check the posted json in the datafiddler it validates post fine. {'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImFkbWluIiwiaWF0IjoxNzExNTM4MjU0LCJleHAiOjE3OTc5MzgyNTR9.oo0FWBOFVRbzv-bA0TzEqzyG4ydAPZL5AkfJRmtF37Y', 'Content-Type': 'application/json'} {"updates": [{"values": [{"path": "electrical.batteries.999.capacity.timeRemaining", "value": 1234}]}]} http://192.168.2.133:3000/signalk/v1/api/ Error writing to Signal K path: api/. Status code: 400 html> <head> <meta charset='utf-8'> <title>SyntaxError: Unexpected token " in JSON at position 0</title> ...... more HTML The stakctrace is: <ul id="stacktrace"><li> at JSON.parse (<anonymous>)</li><li> at createStrictSyntaxError (/usr/local/lib/node_modules/signalk-server/node_modules/body-parser/lib/types/json.js:169:10)</li><li> at parse (/usr/local/lib/node_modules/signalk-server/node_modules/body-parser/lib/types/json.js:86:15)</li><li> at /usr/local/lib/node_modules/signalk-server/node_modules/body-parser/lib/read.js:128:18</li><li> at AsyncResource.runInAsyncScope (node:async_hooks:203:9)</li><li> at invokeCallback (/usr/local/lib/node_modules/signalk-server/node_modules/raw-body/index.js:238:16)</li><li> at done (/usr/local/lib/node_modules/signalk-server/node_modules/raw-body/index.js:227:7)</li><li> at IncomingMessage.onEnd (/usr/local/lib/node_modules/signalk-server/node_modules/raw-body/index.js:287:7)</li> The odd thing is I can successfully post the same json using websockets in Python. My test code for the output above is: (
import requests
import json
# Replace with your Signal K server URL and API token
server_url = "http://192.168.2.133:3000"
api_token = ""
# Path to write to
path = "api/" #----------------------Changed here
value = 120 # Example value in minutes
# Construct URL with path
url = f"{server_url}/signalk/v1/{path}"
# Function to obtain an authentication token
def get_token():
login_url = "http://192.168.2.133:3000/signalk/v1/auth/login"
credentials = {"username": "admin", "password": "******"}
response = requests.post(login_url, json=credentials)
if response.status_code == 200:
return response.json().get("token")
else:
print("Failed to authenticate.")
return None
api_token=get_token()
# Set headers with API token
headers = {
"Authorization": f"Bearer {api_token}",
"Content-Type": "application/json",
}
# Data to send in PUT request
#----------------------Changed here this json works fine int he data fiddler
data = {"updates": [{"values": [{"path": "electrical.batteries.999.capacity.timeRemaining", "value": 1234}]}]}
print(headers)
print(json.dumps(data))
print(url)
try:
# Send PUT request
response = requests.put(url, headers=headers, json=json.dumps(data))
# Check for successful response
if response.status_code == 200:
print("Value written successfully to Signal K path:", path)
else:
print(f"Error writing to Signal K path: {path}. Status code: {response.status_code}")
print("********** RESPONSE **********")
print(response.text)
except requests.exceptions.RequestException as e:
print(f"Error: {e}")
)Perhaps
json.dumps(data)
is stripping the { }
from around the data object. Python isn't one of my strong languages, but in other languages, { }
is shorthand for an object, and would be removed when converting to json.
Try wrapping your data in an extra pair of { }
. eg. {{"updates": [{"values": [{"path": "electrical.batteries.999.capacity.timeRemaining", "value": 1234}]}]}}
I have tried this as well as sending it as a string - and I get the same result. This morning I rewrote the code in micropython and I get the same result as I do in Python and circuit Python. I really don't understand. I communicate with some of my Victron kit in exactly this way but I must be doing something wrong. In signalK is there a way of seeing the 'bad' inbound json string? I can only see log that says
SyntaxError: Unexpected token " in JSON at position 0 at JSON.parse (<anonymous>) at createStrictSyntaxError
I don't know where to go now. Any help from anyone would be appreciated. Below is the output of my code. With the headers, json and response printed to the screen.
{'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImFkbWluIiwiaWF0IjoxNzExOTY0NjI2LCJleHAiOjE3OTgzNjQ2MjZ9.uWqOLURCasix1-LsDRmJSpjC-bkdnlPLjpiMbFnjL90', 'Content-Type': 'application/json'}
{"updates": [{"values": [{"path": "electrical.batteries.999.capacity.timeRemaining", "value": 1234}]}]}
http://192.168.2.133:3000/signalk/v1/api/
Error writing to Signal K path: api/. Status code: 400
** RESPONSE **
<html>
<head>
<meta charset='utf-8'>
<title>SyntaxError: Unexpected token " in JSON at position 0</title>
" is a “ and json must start with a {. I suspect that python has a function to create valid json from a string value. Try generating your json as a string (wrap it in “s) and use that function to generate valid json.
For anyone reading this in the future, it appears that what I am trying to do is not possible. And it is not possible to update a path's value via the rest API and it can only be done via a websockets / UDP connection.
Hi Jonathan, did you get this working with either websockets or UDP? I would like to post a simple path update like you're doing here.