cancel
Showing results for 
Search instead for 
Did you mean: 
SOLVED

Rest API Subscription

Rest API Subscription

David4
New Poster

Hello @CodeShepherd 


Hello all we have been trying to get the complex subscription working, following the guide. but
im able to create the complex subscribe node where i get the code 201 but if i then try to execute a get like the examplei get nothing back. Thanks for you help
With kind regards,
David Maenen

David4_0-1730191034890.png

 

David4_1-1730191034879.png

 

with kinde regards,
David

10 REPLIES 10

CodeShepherd
Community Moderator
Community Moderator

As mentioned in the the how to "How to subscribe to nodes of the ctrlX Data Layer using REST commands via CURL" you will receive a SSE (server sent event) response, so you also have to use a library supporting such kind of communication. As the screenshots are quite small and seems not to include information about the used library to do the the GET it is hard to tell what is going on.

Please also beware that unused subscription rule sets are automatically removed after a 60s timeout.

Hello @CodeShepherd ,
Thanks for the fast reply we are using the API requests "import requests" Hereby the code for the payload and the post. And for the .get "Motion_sub = s.get(BASE_URL + '/automation/api/v2/events/subID')". Yes we are of the fact that after 60s they get removed if unused.
Thanks for the help. 

# Define the payload

payload = {

    "properties": {

        "id": "subID",

        "keepaliveInterval": 60000,

        "publishInterval": 1000,

        "rules": [{

                "rule_type": "Queueing",

                "rule": {

                    "queueSize": 10

                }

            },

            {

                "rule_type": "Sampling",

                "rule": {

                    "samplingInterval": 100000

                }

            },

            {

                "rule_type": "ChangeEvents",

                "rule": {

                    "valueChange": "StatusValueTimestamp"

                }

            }

        ]

    },

    "nodes": ["framework/metrics/system/memavailable-mb"

]

}

 

# Make the POST request

motion_info = s.post(BASE_URL + '/automation/api/v2/events?format=json', json=payload)

 

# Check the response for the POST request

if motion_info.status_code == 201:

    response_data = motion_info.json  # Call the method to get JSON data

    print(response_data)  # Print the response data

else:

    print(f"Error: {motion_info.status_code} - {motion_info.text}")

 

 

Sgilk
Frequent Contributor

@David4 ,

Like @CodeShepherd said, you need a client that supports SSE. Python requests does not. See sseclient-py as an example.

Here is a modification of your code above.

    # Make the POST request
    motion_info = requests.post(url, json=payload, headers=head, verify=False)

    # Check the response for the POST request
    if motion_info.status_code == 201:

        response_data = motion_info.json  # Call the method to get JSON data

        print(response_data)  # Print the response data

    else:
        print(f"Error: {motion_info.status_code} - {motion_info.text}")
    

    url = "https://10.0.2.2:8443/automation/api/v2/events/subID"
    stream_response = requests.get(url, headers=head, verify=False, stream=True)
    client = sseclient.SSEClient(stream_response)

    # Loop forever (while connection "open")
    for event in client.events():
        print ("got a new event from server")
        pprint.pprint(event.data)

 

Hello @Sgilk and @CodeShepherd 
Thank for the help

Hi @Sgilk 
Thanks for the help i do still have the problem where it gets stuck on the .get i think it has somthing to do with where it still uses the import reqeust lib. Again thanks for all the help for some context im still a student so still learning allot in this field so thanks for your patience.

import sseclient

import pprint

import ctypes

import json

import numpy as np

 

import time

from matplotlib import pyplot as plt

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

import requests

BASE_URL = "https://192.168.1.1"

USERNAME = "boschrexroth"

PASSWORD = "boschrexroth"

head = {'Content-Type': 'application/json'}

creds = {"name":USERNAME, "password": PASSWORD}

 

 

# sys.excepthook = customlogger.handle_exception

kernel32 = ctypes.windll.kernel32

kernel32.SetConsoleMode(kernel32.GetStdHandle(-10), 439) #disable the quick edit function of terminal

access_token = None

################### Step 1 ##################### functions

 

 

with requests.post(BASE_URL + '/identity-manager/api/v2/auth/token',headers = head, verify= False, json=creds) as response:

    data = json.loads(response.text)

    token = data['access_token']

# 0.1 - authorization

 

head = {"accept": "application/json", 'Authorization':'Bearer {}'.format(token)}

 

payload = {

    "properties": {

        "id": "subID",

        "keepaliveInterval": 60000,

        "publishInterval": 1000,

        "rules": [{

                "rule_type": "Queueing",

                "rule": {

                    "queueSize": 10

                }

            },

            {

                "rule_type": "Sampling",

                "rule": {

                    "samplingInterval": 1000

                }

            },

            {

                "rule_type": "ChangeEvents",

                "rule": {

                    "valueChange": "StatusValueTimestamp"

                }

            }

        ]

    },

    "nodes": ["motion/axs/X/state/values/actual/pos"

]

}

 

# Make the POST request

motion_info = requests.post(BASE_URL + '/automation/api/v2/events?format=json', json=payload,headers = head, verify = False)

 

# Check the response for the POST request

if motion_info.status_code == 201:

    response_data = motion_info.json  # Call the method to get JSON data

    print(response_data)  # Print the response data

else:

    print(f"Error: {motion_info.status_code} - {motion_info.text}")

 

 

motion_sub = requests.get(BASE_URL + '/automation/api/v2/events/subID',headers = head, stream = True, verify= False)

 

client = sseclient.SSEClient(motion_sub)

if motion_sub.status_code == 200:

    print(motion_sub.json())  # Call the method to get JSON data

else:

    print(f"Error: {motion_sub.status_code} - {motion_sub.text}")

for event in client.events():

    pprint.pprint(event.data)

 

Sgilk
Frequent Contributor

@David4 ,

Can you please post the error messages you are seeing? Maybe you can debug and set a breakpoint on the problem line so you can step over it and view more information.

Thats the strange part. the post i get the message 201 so completed and then with the .get it dousnt give a error because it runs on the .get and dousnt move forward to the next line. Even if i run it via the line for line debug tool it stops at the .get and dousnt want to move forward and eventually it crashes. 

David4_0-1730293856108.png

 

and the strange part is that if i for example remove the headers so it dousnt have authentication it dous give the 401 so it is talking with the datalayer and on the correct position as well. same goes for if i type the path wrong

Sgilk
Frequent Contributor

@David4 ,

Your problem is with parsing the response of the motion subscription as json.

    #print(motion_sub.json())  # INCORRECT
    print(motion_sub.json)     # CORRECT

Hi, yea that was the problem thanks for you help i completely overlooked it. Stupid because i had the same iseu a while back where i programmed json() instead of json.

Icon--AD-black-48x48Icon--address-consumer-data-black-48x48Icon--appointment-black-48x48Icon--back-left-black-48x48Icon--calendar-black-48x48Icon--center-alignedIcon--Checkbox-checkIcon--clock-black-48x48Icon--close-black-48x48Icon--compare-black-48x48Icon--confirmation-black-48x48Icon--dealer-details-black-48x48Icon--delete-black-48x48Icon--delivery-black-48x48Icon--down-black-48x48Icon--download-black-48x48Ic-OverlayAlertIcon--externallink-black-48x48Icon-Filledforward-right_adjustedIcon--grid-view-black-48x48IC_gd_Check-Circle170821_Icons_Community170823_Bosch_Icons170823_Bosch_Icons170821_Icons_CommunityIC-logout170821_Icons_Community170825_Bosch_Icons170821_Icons_CommunityIC-shopping-cart2170821_Icons_CommunityIC-upIC_UserIcon--imageIcon--info-i-black-48x48Icon--left-alignedIcon--Less-minimize-black-48x48Icon-FilledIcon--List-Check-grennIcon--List-Check-blackIcon--List-Cross-blackIcon--list-view-mobile-black-48x48Icon--list-view-black-48x48Icon--More-Maximize-black-48x48Icon--my-product-black-48x48Icon--newsletter-black-48x48Icon--payment-black-48x48Icon--print-black-48x48Icon--promotion-black-48x48Icon--registration-black-48x48Icon--Reset-black-48x48Icon--right-alignedshare-circle1Icon--share-black-48x48Icon--shopping-bag-black-48x48Icon-shopping-cartIcon--start-play-black-48x48Icon--store-locator-black-48x48Ic-OverlayAlertIcon--summary-black-48x48tumblrIcon-FilledvineIc-OverlayAlertwhishlist