0

I setup an the fiware201:iot-sensor inside an Ubuntu 16.04 instance on FIWARE-lab , and am currently building an android application to be able to send commands to access the dummy devices provided by the context provider , i setup a class that formats the data and sends it to the endpoint provided by the tutorial , but i cant seem to get it to work , i get a 422 error whenever i try to send any command.

additional details:
i am using volley -> a package to send post,get requests in android
fiware-lab region : crete

here is the code:


import android.content.Context;
import android.util.Log;

import com.android.volley.AuthFailureError;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;

import java.util.HashMap;
import java.util.Locale;
import java.util.Map;


public class ApiController {
    private String urlString
    public String serverResponse;
    private RequestQueue queue ;

    public ApiController(Context context) {
        //set context variables if required

        serverResponse = "";
        queue = Volley.newRequestQueue(context);


    }

    public void setDevice(String device) {
        this.device = device;
        urlString = "http://myFloatingIp:3001/iot/" +"Lamp001"; // URL to call

}


    public void send() {
        String uri = String.format(Locale.US, urlString);

        // Request a string response from the provided URL.
        StringRequest stringRequest = new StringRequest(Request.Method.POST,uri,
                new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {
                               serverResponse = response;
                    }
                }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
              serverResponse = "Error";
            }
        }
                      ) {
            @Override
            protected Map<String, String> getParams() throws AuthFailureError {
                Map<String,String> params=new HashMap<String,String>();
                params.put("data","urn:ngsi-ld:Lamp:001"@On");
                return params;

            }

            @Override
            public Map<String, String> getHeaders() throws AuthFailureError {
                Map<String,String> headers=new HashMap<String,String>();
                headers.put("Content-Type","text/plain");
                return headers;
            }

        };

// Add the request to the RequestQueue.
        queue.add(stringRequest);
    }


}
Jason Fox
  • 5,115
  • 1
  • 15
  • 34

1 Answers1

0

422 Unprocessable Entity

The server understands the content type of the request entity (hence a 415 Unsupported Media Type status code is inappropriate), and the syntax of the request entity is correct (thus a 400 Bad Request status code is inappropriate) but was unable to process the contained instructions.

So this means that you have set the correct content type, and the payload is understood.

If you look at the code behind the dummy sensors you will see the following:

// Check for a valid device and command
  if (
    _.indexOf(myCache.keys(), deviceId) === -1 ||
    _.indexOf(['on', 'off'], command) === -1
  ) {
    return res.status(422).send(result + NOT_OK);
}

Therefore either the ID of the device or the command is not recognized. The array of dummy devices is initialised on start up

myCache.set('lamp001', LAMP_OFF);
myCache.set('lamp002', LAMP_OFF);
myCache.set('lamp003', LAMP_OFF);
myCache.set('lamp004', LAMP_OFF);

The IDs are case sensitive, hence you should send lamp001 not Lamp001. Yes it could send a more familiar 404. The other half of the statement ensures a 422 is returned if the command is not recognized, you are currently sending On not on

However using the 3001 port directly to send commands is not the right way for a user to access the devices. In the tutorial material the dummy devices are mimicking an Ultralight device listening over HTTP - they are supposed to be connected by an IoT Agent rather than accessed by an end user.

The correct way to set things up is to connect things up following the IoT Agent Tutorial - that way End Users can indirectly access the devices via the Orion context broker and the end user doesn't need to know the protocol and transport used by each device.

Remember, anything could be going on south of the south port - it is up to the IoT Agent to cope with whatever the response comes from the device. However everything will be nicely defined NGSI v2 responses coming out of the North port. If the entity is not registered in the context broker it will return the familiar 404. If the entity is registered, but something strange like a 422 occurs on a command, the command will be left in a pending state since it cannot be processed and so on. May be the device is connected using MQTT and only wakes up to process commands periodically.

To update the state of an entity with a known ID, you merely send a PATCH request to the entity within the context broker. Programmatically, the code can be see here - something like

PATCH http://localhost:1026/v2/entities/'urn:ngsi-ld:lamp001/attrs

With the payload being the data you want to send.

Jason Fox
  • 5,115
  • 1
  • 15
  • 34
  • i tried changing from Lamp001 to lamp001 still i get the same error-> BasicNetwork.performRequest: Unexpected response code 422 for "http://myfloatingip:3001/iot/lamp001" , i know i should be using iot agent but i am doing the fiware 201 for testing purposes for a project . – Mohamed Hatem Feb 01 '19 at 20:55
  • Line 116 is looking for `on` or `off` (case sensitive) - you are sending `On` – Jason Fox Feb 01 '19 at 21:01
  • changed it as well but the problem still presists , what i dont understand is why doesnt this error (422) appear when i send the same command using postman even if i changed upper or lower cases , it runs normally without any problems – Mohamed Hatem Feb 01 '19 at 21:22
  • 1
    It looks to me that your payload is incorrect. Looking at the Ultralight [documentation](https://fiware-iotagent-ul.readthedocs.io/en/latest/usermanual/index.html) you should be sending a **plain text** string. You are sending parameters, you need to override `getBody()` not `getParams()` https://stackoverflow.com/a/26270185/1179828 – Jason Fox Feb 02 '19 at 11:00