Closed AcidRobot closed 5 years ago
What library are you using to create your webthing? Is it one of ours, or is it something custom? I'm guessing you're missing the top-level href
field in your thing description. Can you post your full thing description from http://example.com/lamp?
Alternatively, the links inside your properties may be wrong.
There's a top level href? Is it the alternative link from https://iot.mozilla.org/wot/#web-thing-description :
"rel": "alternate",
"href": "wss://mywebthingserver.com/things/lamp"
},
here is my configs nodejs:
const {
Action,
Event,
Property,
SingleThing,
Thing,
Value,
WebThingServer,
} = require('webthing');
const uuidv4 = require('uuid/v4');
class OverheatedEvent extends Event {
constructor(thing, data) {
super(thing, 'overheated', data);
}
}
class FadeAction extends Action {
constructor(thing, input) {
super(uuidv4(), thing, 'fade', input);
}
performAction() {
return new Promise((resolve) => {
setTimeout(() => {
this.thing.setProperty('brightness', this.input.brightness);
this.thing.addEvent(new OverheatedEvent(this.thing, 102));
resolve();
}, this.input.duration);
});
}
}
function makeThing() {
const thing = new Thing('My Lamp',
['OnOffSwitch', 'Light'],
'A web connected lamp');
thing.addProperty(
new Property(thing,
'on',
new Value(true),
{
'@type': 'OnOffProperty',
title: 'On/Off',
type: 'boolean',
description: 'Whether the lamp is turned on',
}));
thing.addProperty(
new Property(thing,
'brightness',
new Value(50),
{
'@type': 'BrightnessProperty',
title: 'Brightness',
type: 'integer',
description: 'The level of light from 0-100',
minimum: 0,
maximum: 100,
unit: 'percent',
}));
thing.addAvailableAction(
'fade',
{
title: 'Fade',
description: 'Fade the lamp to a given level',
input: {
type: 'object',
required: [
'brightness',
'duration',
],
properties: {
brightness: {
type: 'integer',
minimum: 0,
maximum: 100,
unit: 'percent',
},
duration: {
type: 'integer',
minimum: 1,
unit: 'milliseconds',
},
},
},
},
FadeAction);
thing.addAvailableEvent(
'overheated',
{
description: 'The lamp has exceeded its safe operating temperature',
type: 'number',
unit: 'degree celsius',
});
return thing;
}
function runServer() {
const thing = makeThing();
// If adding more than one thing, use MultipleThings() with a name.
// In the single thing case, the thing's name will be broadcast.
const server = new WebThingServer(new SingleThing(thing), 8888);
process.on('SIGINT', () => {
server.stop().then(() => process.exit()).catch(() => process.exit());
});
server.start().catch(console.error);
}
runServer();
With the code you just gave me, the thing description is located at /
, not at /lamp
.
I'm using a proxy_pass to host it at example.com/lamp
location /lamp/ {
proxy_pass http://localhost:8888/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_cache_bypass $http_upgrade;
}
Is there another way?
That's not going to work. The URLs are all taken from the various links in the thing description.
{
"name": "My Lamp",
"href": "/",
"@context": "https://iot.mozilla.org/schemas",
"@type": [
"OnOffSwitch",
"Light"
],
"properties": {
"on": {
"@type": "OnOffProperty",
"title": "On/Off",
"type": "boolean",
"description": "Whether the lamp is turned on",
"links": [
{
"rel": "property",
"href": "/properties/on"
}
]
},
"brightness": {
"@type": "BrightnessProperty",
"title": "Brightness",
"type": "integer",
"description": "The level of light from 0-100",
"minimum": 0,
"maximum": 100,
"unit": "percent",
"links": [
{
"rel": "property",
"href": "/properties/brightness"
}
]
}
},
"actions": {
"fade": {
"title": "Fade",
"description": "Fade the lamp to a given level",
"input": {
"type": "object",
"required": [
"brightness",
"duration"
],
"properties": {
"brightness": {
"type": "integer",
"minimum": 0,
"maximum": 100,
"unit": "percent"
},
"duration": {
"type": "integer",
"minimum": 1,
"unit": "milliseconds"
}
}
},
"links": [
{
"rel": "action",
"href": "/actions/fade"
}
]
}
},
"events": {
"overheated": {
"description": "The lamp has exceeded its safe operating temperature",
"type": "number",
"unit": "degree celsius",
"links": [
{
"rel": "event",
"href": "/events/overheated"
}
]
}
},
"links": [
{
"rel": "properties",
"href": "/properties"
},
{
"rel": "actions",
"href": "/actions"
},
{
"rel": "events",
"href": "/events"
},
{
"rel": "alternate",
"href": "ws://localhost:8888/"
}
],
"description": "A web connected lamp"
}
See the href
fields inside the various links
arrays. Those are all absolute paths, which is how the gateway will interpret them.
A better option would be to host the thing description on its own virtual host, rather than as a sub-directory.
yeah, unfortunately I'm running it under a tunneling service and having nginx rewrite the things to each endpoint. Could I not just add an
"name": "My Lamp",
"href": "/lamp", // "/" -> "/lamp"
"@context": "https://iot.mozilla.org/schemas",
"@type": [
"OnOffSwitch",
"Light"
],
In that case, what you'll want to do is patch the webthing library. Prefix all of the paths in this code with /lamp
: https://github.com/mozilla-iot/webthing-node/blob/master/lib/server.js#L734-L759
Nevermind, that will only half-solve your problem. There are going to be some pretty invasive changes to make this work.
then it would be available at http://localhost:8888/lamp and thing-url-adapter would query it at http://example.com/lamp?
yeah, that line changing the url to allow the thing to have a subpath works pretty well
Oh, great. Glad that worked.
Alternatively, you could keep your proxy config as is and also proxy /properties
, /actions
, and /events
to the web thing.
The work around from my original comment.
I plan on having multiple things under the same url for example:
server {
listen 80;
server_name example.com;
location /light01/ {
proxy_pass http://192.168.0.101:8888/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_cache_bypass $http_upgrade;
}
location /lamp/ {
proxy_pass http://localhost:8888/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_cache_bypass $http_upgrade;
}
location /light02/ {
proxy_pass http://192.168.0.103:8888/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_cache_bypass $http_upgrade;
}
Could I add them as hrefs to the properties themselves? For example:
"on": {
"@type": "OnOffProperty",
"title": "On/Off",
"type": "boolean",
"description": "Whether the lamp is turned on",
"links": [
{
"rel": "property",
"href": "/lamp/properties/on"
}
]
},
Would you be up for trying out a pull request?
https://github.com/mozilla-iot/webthing-node/pull/86
There's a new parameter you can pass to the WebThingServer
constructor.
yeah, Do I need to add something to the my lamp example posted above?
Change:
const server = new WebThingServer(new SingleThing(thing), 8888);
to:
const server = new WebThingServer(new SingleThing(thing), 8888, null, null, null, '/lamp');
Hey so I pulled it and everything seems to be working.
I did have to change the proxy to the following:
location /lamp/ {
proxy_pass http://localhost:8888/lamp/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_cache_bypass $http_upgrade;
}
Excellent. I'll merge that PR and it will be available when I release v0.12.
If you have a thing at http://example.com/lamp thing-adapter parses out the "/lamp" and cannot connect to device as it tries to send commands to "example.com"
I've written around the issue for my specific url but wanted it to be known.
error:
work around: line 99:
this.baseHref = (url.indexOf('example') !== -1) ? new URL(url) : new URL(url).origin;
line 524:
const baseHref = (url.indexOf('example') !== -1) ? new URL(url) : new URL(url).origin;