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
Roger
Roger6mo ago
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
Johnathan B
Johnathan B6mo ago
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}") )
Roger
Roger6mo ago
A 401 error suggests that the token is invalid or expired.
Johnathan B
Johnathan B6mo ago
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 &quot; in JSON at position 0</title> ...... more HTML The stakctrace is: <ul id="stacktrace"><li> &nbsp; &nbsp;at JSON.parse (&lt;anonymous&gt;)</li><li> &nbsp; &nbsp;at createStrictSyntaxError (/usr/local/lib/node_modules/signalk-server/node_modules/body-parser/lib/types/json.js:169:10)</li><li> &nbsp; &nbsp;at parse (/usr/local/lib/node_modules/signalk-server/node_modules/body-parser/lib/types/json.js:86:15)</li><li> &nbsp; &nbsp;at /usr/local/lib/node_modules/signalk-server/node_modules/body-parser/lib/read.js:128:18</li><li> &nbsp; &nbsp;at AsyncResource.runInAsyncScope (node:async_hooks:203:9)</li><li> &nbsp; &nbsp;at invokeCallback (/usr/local/lib/node_modules/signalk-server/node_modules/raw-body/index.js:238:16)</li><li> &nbsp; &nbsp;at done (/usr/local/lib/node_modules/signalk-server/node_modules/raw-body/index.js:227:7)</li><li> &nbsp; &nbsp;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}") )
Roger
Roger6mo ago
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}]}]}}
Johnathan B
Johnathan B6mo ago
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 &quot; in JSON at position 0</title>
Roger
Roger6mo ago
&quot; 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.
Johnathan B
Johnathan B6mo ago
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.
barnaclebill
barnaclebill4mo ago
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.
Want results from more Discord servers?
Add your server