Web Thing Step-By Step

Struggling to understand how to use this addon !

If I click add new thing, I can then click ‘add by url’ but any url I enter I get a 404 not found error message, even if I know for sure that this is a valid url.

If I enter the url of the gateway http://192.168.0.20/ I also get a 404 not found.

But let’s say I add a url, then what do I do ???

OK, lets say I have a nodejs web server running and listening on port 3000, it simply accepts requests and sends a simple echo response.

When I enter the url in ‘add thing’ I get a 404 even though I can access vi a web browser !

So how exactly does this work ?? - assuming that I can customise my response to url requests on this web server and perform i/o actions and reply to the iot-gateway, what is needed for the most basic request/response so I can at least get something working.

Just to try and figure this out, I had the server respond with a JSON array of things when doing a GET to /, but I have no idea if this is correct:

[
  "thing-a",
  "thing-b",
  "thing-c"
]

Not having much success today :frowning:

OK, this may be obvious to everyone else except me.

Settings/addons/webthing > Configure thing-url-adapter - this adds the server url, and mozilla-iot will poll this url (root) to get a list of devices: GET http://myhost/

The server then responds with a list of things:

[{
    "@context": "https://iot.mozilla.org/schemas/",
    "@type": ["Light", "OnOffSwitch"],
    "name":"LED",
    "description": "LED",
    "properties": {
    
      "on": {
        "@type": "OnOffProperty",
        "type": "boolean",
        "href": "/things/led/properties/on",
        "value": false
      }
    }
  }
]

the gateway will then query the webserver for the thing status:

GET http://myhost//things/led/properties/on

The server then responds with the status:

{"led":true/false}

If you toggle the thing on/off, then the iot-gateway sends a POST instead of a GET, the web server can then perform it’s I/O and reply with the same status as for the query.

I don’t know if this is the correct usage, but it seems to work, now I understand this I can also create web server devices on other platforms such as micropython.

This is what I was trying to understand.

When you create your own web things that you want to associate with the gateway, if they are native web things you should be able to see their thing description at their URL (IP address), like the attached image shows. If that doesn’t load correctly in your browser then there’s likely a syntax error in the JSON thing description.

Why is it that when I switch a web-thing LED on and off, the request is PUT properties and not POST actions ???

This is what is sent to the things server when I toggle the LED:

PUT /things/led/properties/on

Interesting question. I had to search it and i found a very good explanation: https://www.keycdn.com/support/put-vs-post

@Novski - Thanks so much for helping, I looked at the link, but why is the gateway sending a PUT instead of a POST when I toggle the on/off switch ? - surely it should send a POST action and not a PUT property when changing the value of a property ?

Because the Staus (on/off) is known by the gateway it can replace it with the opposite.

If the State of the thing would not be known, then a Post is necessary to tell the thing to first check and then change it.

But the gateway should always know the state of a thing…

Hi @diginfo,

The gateway expects web things to follow the Web Thing API which means that the URL you enter should resolve to a Web Thing Description in JSON format (with a Content-Type: application/json header) which describes the web thing’s properties, actions and events.

The Web Thing REST API describes the RESTful API for communicating with a web thing. You can GET a property to read it and PUT a property to write it, or invoke an action with a POST for example. Setting a property is a PUT because it is overwriting the resource at the property URL with the payload of the request, whereas invoking an action is a POST because it’s create a new (action request) resource.

The specification says that “Actions are used when the setting of a property alone is not sufficient to affect a required change in state.”

I hope this helps.

Made a lot of progress with this on a custom nodejs web server and on MicroPython using my own web server ‘lite’ and have it working, with the exception of the “things” request.

For some reason, the system only recognises the second thing ‘GRN-13’ and never lists ‘RED-12’ as a thing that can be added:

  [
  {
    "name": "RED-12",
    "id": "RED-12",
    "@type": [
      "Light",
      "OnOffSwitch"
    ],
    "pin": 12,
    "@context": "https://iot.mozilla.org/schemas/",
    "description": "RED-12",
    "properties": {
      "on": {
        "href": "/things/RED-12/properties/on",
        "@type": "OnOffProperty",
        "type": "boolean",
        "value": false
      }
    }
  },
  {
    "name": "GRN-13",
    "id": "GRN-13",
    "@type": [
      "Light",
      "OnOffSwitch"
    ],
    "pin": 13,
    "@context": "https://iot.mozilla.org/schemas/",
    "description": "GRN-13",
    "properties": {
      "on": {
        "href": "/things/GRN-13/properties/on",
        "@type": "OnOffProperty",
        "type": "boolean",
        "value": false
      }
    }
  }
]

I can add the ‘GRN-13’ device and control it, but ‘RED-12’ is not listed and therefore cannot be added.

Any idea what is wrong ?

I thought that maybe it was because I did not include an “id”, however I added that into the definition and it makes no difference :frowning:

You can try adding your things individually. Click on “Add by URL…” on the screen where you add new things, then type http://<ip address>:<port>/things/RED-12, for instance.

Thanks, I can do that, but is this a bug with thing-url-adapter whereby it only parses the last thing in the things json array ??

I can manually add the device by URL and it works as expected, but it seems that the “title” property is needed as this is used by the discovery script to populate the input fields and thing’s name (or title) !

Also, I notice from the logs, that only one of the things is being polled (I have set poll freq to 15 seconds) every 15 seconds, the other device is not polled at all.

Hmm, interesting. I’ll look into this closer and will post back if I find something.

I’ve been doing some testing (using webthing-python) and I don’t have problems with discovering or polling multiple devices. Are you using webthing-upy or your own server implementation? It sounds like it may be your own.

Also, you need to add each of your things individually. Have you done that?

Yes I am using my own web server, see a few posts above where I show the JSON output from things: http://mydevice/

When none of the devices from my web server are added, and I press the + add devices, only the second thing is discovered (RED-12), I can then select the save button next to the discovered thing (RED-12) and add it, note that GRN-13 is not listed at all, the code cannot see GRN-13.

If I then re-run the discovery after adding the only available thing, nothing new is discovered, but I can manually add the second device (GRN-13) by URL http://192.168.0.186/things/GRN-13

I can then control both devices, and switch both on and off, but when I monitor the logs from my server, the Mozilla gateway is polling one of the devices TWICE (’/things/GRN-13/properties/on’) and no requests are ever received to poll RED-12, i.e 2 requests are received to poll ‘/things/GRN-13/properties/on’.

here is my things JSON again (http://192.168.0.186/):

[
  {
    "id": "http://192.168.0.186/things/RED-12",
    "properties": {
      "on": {
        "href": "/things/RED-12/properties/on",
        "@type": "OnOffProperty",
        "type": "boolean",
        "value": false
      }
    },
    "@context": "https://iot.mozilla.org/schemas/",
    "name": "RED-12",
    "description": "RED-12",
    "@type": [
      "Light",
      "OnOffSwitch"
    ],
    "title": "RED-12",
    "pin": 12
  },
  {
    "id": "http://192.168.0.186/things/GRN-13",
    "properties": {
      "on": {
        "href": "/things/GRN-13/properties/on",
        "@type": "OnOffProperty",
        "type": "boolean",
        "value": false
      }
    },
    "@context": "https://iot.mozilla.org/schemas/",
    "name": "GRN-13",
    "description": "GRN-13",
    "@type": [
      "Light",
      "OnOffSwitch"
    ],
    "title": "GRN-13",
    "pin": 13
  }
]

I have opened up the port to this device and sent you a personal message with the IP address and port.

Ok, so I see a couple of things that may be causing issues.

  1. Your server is responding with Content-Type: text/html.
  2. You should really includes a links array in your thing description and property descriptions. See the examples here. href is the old way of doing things.
  3. name is no longer used by the gateway, although that wouldn’t really cause issues. Ditto for pin.
  4. Your properties should probably include a title, and omit the value.

For discovery, how are you broadcasting your device via mDNS? What is the service type, what is the path, etc.?

Do you see any errors in your gateway log? Relevant items would be prefixed by thing-url:.

Thanks;

  1. My server will respond with whatever content type is requested using the Content-Type specified in the request header, so if you just use a browser then it will respond using text which the browser requested, if the request asks for JSON then it will reply with that instead.

  2. OK but given that resources are limited on MicroPython, I would prefer to only include what is essential.

3&4. pin and value are used by me and can be ignored by the gateway ?

I think discovery is done by the web-things plugin right ?? - doesn’t it make a http request to the url root to get a list of things ??

If you add this url to your own gateway setup, does it all work as expected ??

  1. You should be looking at the Accept header on the request, which should be application/json. Please respond with that. Your server is working fine when responding to the add-on. It was only in my browser that it was responding as text/html.
  2. links should be considered essential, as href is no longer in the spec.
  3. Yes, those will be ignored by the gateway.
  4. title is used by the gateway, but value will not be.

The adapter discovers new devices via mDNS. See comment here. This is what makes things automatically appear in the new things list. So, if you want that to work, you need to broadcast as _webthing._tcp, with a path=/ TXT record.

And yes, if I add your IP address manually, things are working fine. If I watch things in Wireshark, I see both endpoints being polled separately.

EDIT: For an example of the mDNS bit, see here: https://github.com/mozilla-iot/webthing-upy/blob/master/webthing/server.py#L235-L241