diff --git a/examples/quickstart/README.md b/examples/quickstart/README.md deleted file mode 100644 index 0183dad5f..000000000 --- a/examples/quickstart/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Quick Start Things - -This set of Things can be used to build mashup applications for a smart home scenario. -These Things are: - -- Simple coffee machine that can take an order to brew a coffee. -- Presence sensor that emits an event when a person is detected. -- Smart clock that runs 60 times faster than real time, where 1 hour happens in 1 minute. - -These Things are hosted on plugfest.thingweb.io but can be also self-hosted. diff --git a/examples/quickstart/presence-sensor.js b/examples/quickstart/presence-sensor.js deleted file mode 100644 index 72670855f..000000000 --- a/examples/quickstart/presence-sensor.js +++ /dev/null @@ -1,59 +0,0 @@ -"use strict"; -/******************************************************************************** - * Copyright (c) 2023 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the W3C Software Notice and - * Document License (2015-05-13) which is available at - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document. - * - * SPDX-License-Identifier: EPL-2.0 OR W3C-20150513 - ********************************************************************************/ -// This is an example Thing script which is a simple presence detector -// It fires an event when it detects a person (mocked as every 5 second) -const core_1 = require("@node-wot/core"); -const binding_mqtt_1 = require("@node-wot/binding-mqtt"); -// create Servient add MQTT binding with port configuration -const servient = new core_1.Servient(); -servient.addServer(new binding_mqtt_1.MqttBrokerServer({ uri: "mqtt://test.mosquitto.org" })); -servient.start().then((WoT) => { - WoT.produce({ - title: "PresenceSensor", - description: "Thing that can detect presence of human nearby", - support: "https://github.com/eclipse-thingweb/node-wot/", - "@context": "https://www.w3.org/2022/wot/td/v1.1", - events: { - presenceDetected: { - title: "Presence Detected", - description: - "An event that is emitted when a person is detected in the room. It is mocked and emitted every 5 seconds", - data: { - type: "number", - title: "Distance", - minimum: 55, - maximum: 1200, - }, - }, - }, - }) - .then((thing) => { - console.log("Produced " + thing.getThingDescription().title); - // expose the thing - thing.expose().then(() => { - console.info(thing.getThingDescription().title + " ready"); - // mocking the detection with an event sent every 5 seconds, with a random distance - setInterval(() => { - const distance = Math.random() * (1200 - 55) + 55; - thing.emitEvent("presenceDetected", distance); - console.info("Emitted presence with distance ", distance); - }, 5000); - }); - }) - .catch((e) => { - console.log(e); - }); -}); diff --git a/examples/quickstart/simple-coffee-machine.js b/examples/quickstart/simple-coffee-machine.js deleted file mode 100644 index 136e3ee1f..000000000 --- a/examples/quickstart/simple-coffee-machine.js +++ /dev/null @@ -1,203 +0,0 @@ -"use strict"; -/******************************************************************************** - * Copyright (c) 2023 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the W3C Software Notice and - * Document License (2015-05-13) which is available at - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document. - * - * SPDX-License-Identifier: EPL-2.0 OR W3C-20150513 - ********************************************************************************/ -// This is an example Thing script which is a simple coffee machine. -// You can order coffee and see the status of the resources -const core_1 = require("@node-wot/core"); -const binding_http_1 = require("@node-wot/binding-http"); -// create Servient add HTTP binding with port configuration -const servient = new core_1.Servient(); -// const staticAddress = "plugfest.thingweb.io"; -const staticAddress = "localhost"; // use this for testing locally -const httpPort = 8081; -servient.addServer( - new binding_http_1.HttpServer({ - port: httpPort, - }) -); -core_1.Helpers.setStaticAddress(staticAddress); -let waterAmount = 1000; -let beansAmount = 1000; -let milkAmount = 1000; -// promisify timeout since it does not return a promise -function timeout(ms) { - return new Promise((resolve) => setTimeout(resolve, ms)); -} -servient.start().then((WoT) => { - WoT.produce({ - title: "Coffee Machine", - description: "A simple coffee machine that can be interacted over the Internet", - support: "https://github.com/eclipse-thingweb/node-wot/", - "@context": "https://www.w3.org/2022/wot/td/v1.1", - properties: { - resources: { - readOnly: true, - observable: true, - type: "object", - properties: { - water: { - type: "integer", - minimum: 0, - maximum: 1000, - }, - beans: { - type: "integer", - minimum: 0, - maximum: 1000, - }, - milk: { - type: "integer", - minimum: 0, - maximum: 1000, - }, - }, - }, - }, - actions: { - brew: { - synchronous: true, - input: { - type: "string", - enum: ["espresso", "cappuccino", "americano"], - }, - }, - refill: { - synchronous: true, - input: { - type: "array", - items: { - type: "string", - enum: ["water", "beans", "milk"], - }, - }, - }, - }, - events: { - resourceEmpty: { - data: { - type: "array", - items: { - type: "string", - enum: ["water", "beans", "milk"], - }, - }, - }, - }, - }) - .then((thing) => { - console.log("Produced " + thing.getThingDescription().title); - thing.setPropertyReadHandler("resources", async () => { - return { - water: waterAmount, - beans: beansAmount, - milk: milkAmount, - }; - }); - thing.setActionHandler("brew", async (params, options) => { - const coffeeType = await params.value(); - console.info("received coffee order of ", coffeeType); - if (coffeeType === "espresso") { - if (waterAmount <= 10 || beansAmount <= 10) { - throw new Error("Not enough water or beans"); - } else { - await timeout(1000); - waterAmount = waterAmount - 10; - beansAmount = beansAmount - 10; - thing.emitPropertyChange("resources"); - const resourceEvent = []; - if (waterAmount <= 10) { - resourceEvent.push("water"); - } - if (beansAmount <= 10) { - resourceEvent.push("beans"); - } - if (resourceEvent.length > 0) { - thing.emitEvent("resourceEmpty", resourceEvent); - } - return undefined; - } - } else if (coffeeType === "cappuccino") { - if (waterAmount <= 20 || beansAmount <= 25 || milkAmount <= 15) { - throw new Error("Not enough water or beans"); - } else { - await timeout(2000); - waterAmount = waterAmount - 15; - beansAmount = beansAmount - 20; - milkAmount = milkAmount - 10; - thing.emitPropertyChange("resources"); - const resourceEvent = []; - if (waterAmount <= 10) { - resourceEvent.push("water"); - } - if (beansAmount <= 10) { - resourceEvent.push("beans"); - } - if (milkAmount <= 10) { - resourceEvent.push("milk"); - } - if (resourceEvent.length > 0) { - thing.emitEvent("resourceEmpty", resourceEvent); - } - return undefined; - } - } else if (coffeeType === "americano") { - if (waterAmount <= 35 || beansAmount <= 10) { - throw new Error("Not enough water or beans"); - } else { - await timeout(2000); - waterAmount = waterAmount - 30; - beansAmount = beansAmount - 10; - thing.emitPropertyChange("resources"); - const resourceEvent = []; - if (waterAmount <= 10) { - resourceEvent.push("water"); - } - if (beansAmount <= 10) { - resourceEvent.push("beans"); - } - if (resourceEvent.length > 0) { - thing.emitEvent("resourceEmpty", resourceEvent); - } - return undefined; - } - } else { - throw new Error("Wrong coffee input"); - } - }); - thing.setActionHandler("refill", async (params, options) => { - const selectedResource = await params.value(); - console.info("received refill order of ", selectedResource); - if (selectedResource.indexOf("water") !== -1) { - waterAmount = 1000; - } - if (selectedResource.indexOf("beans") !== -1) { - beansAmount = 1000; - } - if (selectedResource.indexOf("milk") !== -1) { - milkAmount = 1000; - } - thing.emitPropertyChange("resources"); - return undefined; - }); - // expose the thing - thing.expose().then(() => { - console.info(thing.getThingDescription().title + " ready"); - console.info("TD available at http://" + staticAddress + ":" + httpPort); - }); - }) - .catch((e) => { - console.log(e); - }); -}); diff --git a/examples/quickstart/smart-clock.js b/examples/quickstart/smart-clock.js deleted file mode 100644 index b235c4356..000000000 --- a/examples/quickstart/smart-clock.js +++ /dev/null @@ -1,87 +0,0 @@ -"use strict"; -/******************************************************************************** - * Copyright (c) 2023 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the W3C Software Notice and - * Document License (2015-05-13) which is available at - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document. - * - * SPDX-License-Identifier: EPL-2.0 OR W3C-20150513 - ********************************************************************************/ -// This is an example Thing which is a smart clock that runs 60 times faster than real time, where 1 hour happens in 1 minute. -const core_1 = require("@node-wot/core"); -const binding_coap_1 = require("@node-wot/binding-coap"); -// create Servient add CoAP binding with port configuration -const servient = new core_1.Servient(); -servient.addServer(new binding_coap_1.CoapServer(5686)); -core_1.Helpers.setStaticAddress("plugfest.thingweb.io"); // comment this out if you are testing locally -let minuteCounter = 0; -let hourCounter = 0; -async function timeCount(thing) { - for (minuteCounter = 0; minuteCounter < 59; minuteCounter++) { - // if we have <60, we can get a 15:60. - await new Promise((resolve) => setTimeout(resolve, 1000)); // sleep - thing.emitPropertyChange("time"); - } - console.info({ - hour: hourCounter, - minute: minuteCounter, - }); - hourCounter++; - if (hourCounter === 24) { - hourCounter = 0; - } -} -servient.start().then((WoT) => { - WoT.produce({ - title: "Smart Clock", - description: "a smart clock that runs 60 times faster than real time, where 1 hour happens in 1 minute.", - support: "https://github.com/eclipse-thingweb/node-wot/", - "@context": "https://www.w3.org/2022/wot/td/v1.1", - properties: { - time: { - readOnly: true, - observable: true, - type: "object", - properties: { - minute: { - type: "integer", - minimum: 0, - maximum: 59, - }, - hour: { - type: "integer", - minimum: 0, - maximum: 23, - }, - }, - }, - }, - }) - .then(async (thing) => { - console.log("Produced " + thing.getThingDescription().title); - thing.setPropertyReadHandler("time", async () => { - return { - hour: hourCounter, - minute: minuteCounter, - }; - }); - timeCount(thing); - setInterval(async () => { - timeCount(thing); - thing.emitPropertyChange("time"); - }, 61000); // if this is 60s, we never leave the for loop - // expose the thing - thing.expose().then(() => { - console.info(thing.getThingDescription().title + " ready"); - }); - }) - .catch((e) => { - console.log(e); - }); -}); diff --git a/examples/scripts/smart-coffee-machine-client.conf.json b/examples/scripts/smart-coffee-machine-client.conf.json deleted file mode 100644 index 1de0fd1ff..000000000 --- a/examples/scripts/smart-coffee-machine-client.conf.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "http": { - "allowSelfSigned": true - }, - "credentials": { - "urn:dev:wot:example:smart-coffee-machine": { - "clientId": "node-wot", - "clientSecret": "isgreat!" - } - } -} diff --git a/examples/scripts/smart-coffee-machine-client.js b/examples/scripts/smart-coffee-machine-client.js deleted file mode 100644 index b8133e139..000000000 --- a/examples/scripts/smart-coffee-machine-client.js +++ /dev/null @@ -1,85 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2022 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the W3C Software Notice and - * Document License (2015-05-13) which is available at - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document. - * - * SPDX-License-Identifier: EPL-2.0 OR W3C-20150513 - ********************************************************************************/ -// This is an example of Web of Things consumer ("client" mode) Thing script. -// It considers a fictional smart coffee machine in order to demonstrate the capabilities of Web of Things. -// An accompanying tutorial is available at http://www.thingweb.io/smart-coffee-machine.html. -// Print data and an accompanying message in a distinguishable way -function log(msg, data) { - console.info("======================"); - console.info(msg); - console.dir(data); - console.info("======================"); -} -WoT.requestThingDescription("http://127.0.0.1:8080/smart-coffee-machine").then(async (td) => { - try { - const thing = await WoT.consume(td); - log("Thing Description:", td); - // Read property allAvailableResources - let allAvailableResources = await (await thing.readProperty("allAvailableResources")).value(); - log("allAvailableResources value is:", allAvailableResources); - // Now let's change water level to 80 - await thing.writeProperty("availableResourceLevel", 80, { uriVariables: { id: "water" } }); - // And see that the water level has changed - const waterLevel = await ( - await thing.readProperty("availableResourceLevel", { uriVariables: { id: "water" } }) - ).value(); - log("waterLevel value after change is:", waterLevel); - // This can also be seen in allAvailableResources property - allAvailableResources = await (await thing.readProperty("allAvailableResources")).value(); - log("allAvailableResources value after change is:", allAvailableResources); - // It's also possible to set a client-side handler for observable properties - thing.observeProperty("maintenanceNeeded", async (data) => { - log("maintenanceNeeded property has changed! New value is:", await data.value()); - }); - // Now let's make 3 cups of latte! - const makeCoffee = await thing.invokeAction("makeDrink", undefined, { - uriVariables: { drinkId: "latte", size: "l", quantity: 3 }, - }); - const makeCoffeep = await (makeCoffee === null || makeCoffee === void 0 ? void 0 : makeCoffee.value()); - if (makeCoffeep.result != null) { - log("Enjoy your drink!", makeCoffeep); - } else { - log("Failed making your drink:", makeCoffeep); - } - // See how allAvailableResources property value has changed - allAvailableResources = await (await thing.readProperty("allAvailableResources")).value(); - log("allAvailableResources value is:", allAvailableResources); - // Let's add a scheduled task - const scheduledTask = await thing.invokeAction("setSchedule", { - drinkId: "espresso", - size: "m", - quantity: 2, - time: "10:00", - mode: "everyday", - }); - const scheduledTaskp = await (scheduledTask === null || scheduledTask === void 0 - ? void 0 - : scheduledTask.value()); - log(scheduledTaskp.message, scheduledTaskp); - // See how it has been added to the schedules property - const schedules = await (await thing.readProperty("schedules")).value(); - log("schedules value: ", schedules); - // Let's set up a handler for outOfResource event - thing.subscribeEvent("outOfResource", async (data) => { - // Here we are simply logging the message when the event is emitted - // But, of course, could have a much more sophisticated handler - log("outOfResource event:", await data.value()); - }); - // fire property change for maintenanceNeeded - await thing.writeProperty("servedCounter", 1001); - } catch (err) { - console.error("Script error:", err); - } -}); diff --git a/examples/scripts/smart-coffee-machine.js b/examples/scripts/smart-coffee-machine.js deleted file mode 100644 index 9f039eede..000000000 --- a/examples/scripts/smart-coffee-machine.js +++ /dev/null @@ -1,399 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2022 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the W3C Software Notice and - * Document License (2015-05-13) which is available at - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document. - * - * SPDX-License-Identifier: EPL-2.0 OR W3C-20150513 - ********************************************************************************/ -// This is an example of Web of Things producer ("server" mode) Thing script. -// It considers a fictional smart coffee machine in order to demonstrate the capabilities of Web of Things. -// An accompanying tutorial is available at http://www.thingweb.io/smart-coffee-machine.html. -let allAvailableResources; -let possibleDrinks; -let maintenanceNeeded; -let schedules; -let servedCounter; -function readFromSensor(sensorType) { - // Actual implementation of reading data from a sensor can go here - // For the sake of example, let's just return a value - return 100; -} -function notify(subscribers, msg) { - // Actual implementation of notifying subscribers with a message can go here - console.log(msg); -} -WoT.produce({ - title: "Smart-Coffee-Machine", - description: `A smart coffee machine with a range of capabilities. -A complementary tutorial is available at http://www.thingweb.io/smart-coffee-machine.html.`, - support: "https://github.com/eclipse-thingweb/node-wot/", - properties: { - allAvailableResources: { - type: "object", - description: `Current level of all available resources given as an integer percentage for each particular resource. -The data is obtained from the machine's sensors but can be set manually via the availableResourceLevel property in case the sensors are broken.`, - readOnly: true, - properties: { - water: { - type: "integer", - minimum: 0, - maximum: 100, - }, - milk: { - type: "integer", - minimum: 0, - maximum: 100, - }, - chocolate: { - type: "integer", - minimum: 0, - maximum: 100, - }, - coffeeBeans: { - type: "integer", - minimum: 0, - maximum: 100, - }, - }, - }, - availableResourceLevel: { - type: "number", - description: `Current level of a particular resource. Requires resource id variable as uriVariables. -The property can also be overridden, which also requires resource id as uriVariables.`, - uriVariables: { - id: { - type: "string", - enum: ["water", "milk", "chocolate", "coffeeBeans"], - }, - }, - }, - possibleDrinks: { - type: "array", - description: `The list of possible drinks in general. Doesn't depend on the available resources.`, - readOnly: true, - items: { - type: "string", - }, - }, - servedCounter: { - type: "integer", - description: `The total number of served beverages.`, - minimum: 0, - }, - maintenanceNeeded: { - type: "boolean", - description: `Shows whether a maintenance is needed. The property is observable. Automatically set to true when the servedCounter property exceeds 1000.`, - observable: true, - }, - schedules: { - type: "array", - description: `The list of scheduled tasks.`, - readOnly: true, - items: { - type: "object", - properties: { - drinkId: { - type: "string", - description: `Defines what drink to make, drinkId is one of possibleDrinks property values, e.g. latte.`, - }, - size: { - type: "string", - description: `Defines the size of a drink, s = small, m = medium, l = large.`, - enum: ["s", "m", "l"], - }, - quantity: { - type: "integer", - description: `Defines how many drinks to make, ranging from 1 to 5.`, - minimum: 1, - maximum: 5, - }, - time: { - type: "string", - description: `Defines the time of the scheduled task in 24h format, e.g. 10:00 or 21:00.`, - }, - mode: { - type: "string", - description: `Defines the mode of the scheduled task, e.g. once or everyday. All the possible values are given in the enum field of this Thing Description.`, - enum: [ - "once", - "everyday", - "everyMo", - "everyTu", - "everyWe", - "everyTh", - "everyFr", - "everySat", - "everySun", - ], - }, - }, - }, - }, - }, - actions: { - makeDrink: { - description: `Make a drink from available list of beverages. Accepts drink id, size and quantity as uriVariables. -Brews one medium americano if no uriVariables are specified.`, - uriVariables: { - drinkId: { - type: "string", - description: `Defines what drink to make, drinkId is one of possibleDrinks property values, e.g. latte.`, - }, - size: { - type: "string", - description: `Defines the size of a drink, s = small, m = medium, l = large.`, - enum: ["s", "m", "l"], - }, - quantity: { - type: "integer", - description: `Defines how many drinks to make, ranging from 1 to 5.`, - minimum: 1, - maximum: 5, - }, - }, - output: { - type: "object", - description: `Returns true/false and a message when all invoked promises are resolved (asynchronous).`, - properties: { - result: { - type: "boolean", - }, - message: { - type: "string", - }, - }, - }, - }, - setSchedule: { - description: `Add a scheduled task to the schedules property. Accepts drink id, size, quantity, time and mode as body of a request. -Assumes one medium americano if not specified, but time and mode are mandatory fields.`, - input: { - type: "object", - properties: { - drinkId: { - type: "string", - description: `Defines what drink to make, drinkId is one of possibleDrinks property values, e.g. latte.`, - }, - size: { - type: "string", - description: `Defines the size of a drink, s = small, m = medium, l = large.`, - enum: ["s", "m", "l"], - }, - quantity: { - type: "integer", - description: `Defines how many drinks to make, ranging from 1 to 5.`, - minimum: 1, - maximum: 5, - }, - time: { - type: "string", - description: `Defines the time of the scheduled task in 24h format, e.g. 10:00 or 21:00.`, - }, - mode: { - type: "string", - description: `Defines the mode of the scheduled task, e.g. once or everyday. All the possible values are given in the enum field of this Thing Description.`, - enum: [ - "once", - "everyday", - "everyMo", - "everyTu", - "everyWe", - "everyTh", - "everyFr", - "everySat", - "everySun", - ], - }, - }, - required: ["time", "mode"], - }, - output: { - type: "object", - description: `Returns true/false and a message when all invoked promises are resolved (asynchronous).`, - properties: { - result: { - type: "boolean", - }, - message: { - type: "string", - }, - }, - }, - }, - }, - events: { - outOfResource: { - description: `Out of resource event. Emitted when the available resource level is not sufficient for a desired drink.`, - data: { - type: "string", - }, - }, - }, -}) - .then((thing) => { - // Initialize the property values - allAvailableResources = { - water: readFromSensor("water"), - milk: readFromSensor("milk"), - chocolate: readFromSensor("chocolate"), - coffeeBeans: readFromSensor("coffeeBeans"), - }; - possibleDrinks = ["espresso", "americano", "cappuccino", "latte", "hotChocolate", "hotWater"]; - maintenanceNeeded = false; - schedules = []; - thing.setPropertyReadHandler("allAvailableResources", async () => allAvailableResources); - thing.setPropertyReadHandler("possibleDrinks", async () => possibleDrinks); - thing.setPropertyReadHandler("maintenanceNeeded", async () => maintenanceNeeded); - thing.setPropertyReadHandler("schedules", async () => schedules); - // Override a write handler for servedCounter property, - // raising maintenanceNeeded flag when the value exceeds 1000 drinks - thing.setPropertyWriteHandler("servedCounter", async (val) => { - servedCounter = await val.value(); - if (servedCounter > 1000) { - maintenanceNeeded = true; - thing.emitPropertyChange("maintenanceNeeded"); - // Notify a "maintainer" when the value has changed - // (the notify function here simply logs a message to the console) - notify( - "admin@coffeeMachine.com", - `maintenanceNeeded property has changed, new value is: ${maintenanceNeeded}` - ); - } - }); - // Now initialize the servedCounter property - servedCounter = readFromSensor("servedCounter"); - // Override a write handler for availableResourceLevel property, - // utilizing the uriVariables properly - thing.setPropertyWriteHandler("availableResourceLevel", async (val, options) => { - // Check if uriVariables are provided - if (options && typeof options === "object" && "uriVariables" in options) { - const uriVariables = options.uriVariables; - if ("id" in uriVariables) { - const id = uriVariables.id; - allAvailableResources[id] = await val.value(); - return; - } - } - throw Error("Please specify id variable as uriVariables."); - }); - // Override a read handler for availableResourceLevel property, - // utilizing the uriVariables properly - thing.setPropertyReadHandler("availableResourceLevel", async (options) => { - // Check if uriVariables are provided - if (options && typeof options === "object" && "uriVariables" in options) { - const uriVariables = options.uriVariables; - if ("id" in uriVariables) { - const id = uriVariables.id; - return allAvailableResources[id]; - } - } - throw Error("Please specify id variable as uriVariables."); - }); - // Set up a handler for makeDrink action - thing.setActionHandler("makeDrink", async (_params, options) => { - // Default values - let drinkId = "americano"; - let size = "m"; - let quantity = 1; - // Size quantifiers - const sizeQuantifiers = { s: 0.1, m: 0.2, l: 0.3 }; - // Drink recipes showing the amount of a resource consumed for a particular drink - const drinkRecipes = { - espresso: { - water: 1, - milk: 0, - chocolate: 0, - coffeeBeans: 2, - }, - americano: { - water: 2, - milk: 0, - chocolate: 0, - coffeeBeans: 2, - }, - cappuccino: { - water: 1, - milk: 1, - chocolate: 0, - coffeeBeans: 2, - }, - latte: { - water: 1, - milk: 2, - chocolate: 0, - coffeeBeans: 2, - }, - hotChocolate: { - water: 0, - milk: 0, - chocolate: 1, - coffeeBeans: 0, - }, - hotWater: { - water: 1, - milk: 0, - chocolate: 0, - coffeeBeans: 0, - }, - }; - // Check if uriVariables are provided - if (options && typeof options === "object" && "uriVariables" in options) { - const uriVariables = options.uriVariables; - drinkId = "drinkId" in uriVariables ? uriVariables.drinkId : drinkId; - size = "size" in uriVariables ? uriVariables.size : size; - quantity = "quantity" in uriVariables ? uriVariables.quantity : quantity; - } - // Calculate the new level of resources - const newResources = Object.assign({}, allAvailableResources); - newResources.water -= Math.ceil(quantity * sizeQuantifiers[size] * drinkRecipes[drinkId].water); - newResources.milk -= Math.ceil(quantity * sizeQuantifiers[size] * drinkRecipes[drinkId].milk); - newResources.chocolate -= Math.ceil(quantity * sizeQuantifiers[size] * drinkRecipes[drinkId].chocolate); - newResources.coffeeBeans -= Math.ceil(quantity * sizeQuantifiers[size] * drinkRecipes[drinkId].coffeeBeans); - // Check if the amount of available resources is sufficient to make a drink - for (const resource in newResources) { - if (newResources[resource] <= 0) { - return new Promise((resolve, reject) => { - thing.emitEvent("outOfResource", `Low level of ${resource}: ${newResources[resource]}%`); - return { result: false, message: `${resource} level is not sufficient` }; - }); - } - } - // Now store the new level of allAvailableResources - allAvailableResources = newResources; - servedCounter = servedCounter + quantity; - // Finally deliver the drink - return { result: true, message: `Your ${drinkId} is in progress!` }; - }); - // Set up a handler for setSchedule action - thing.setActionHandler("setSchedule", async (params, options) => { - const paramsp = await params.value(); // : any = await Helpers.parseInteractionOutput(params); - // Check if uriVariables are provided - if (paramsp != null && typeof paramsp === "object" && "time" in paramsp && "mode" in paramsp) { - // Use default values if not provided - paramsp.drinkId = "drinkId" in paramsp ? paramsp.drinkId : "americano"; - paramsp.size = "size" in paramsp ? paramsp.size : "m"; - paramsp.quantity = "quantity" in paramsp ? paramsp.quantity : 1; - // Now add a new schedule - schedules.push(paramsp); - return { result: true, message: `Your schedule has been set!` }; - } - return new Promise((resolve, reject) => { - resolve({ result: false, message: `Please provide all the required parameters: time and mode.` }); - }); - }); - // Finally expose the thing - thing.expose().then(() => { - console.info(`${thing.getThingDescription().title} ready`); - }); - console.log(`Produced ${thing.getThingDescription().title}`); - }) - .catch((e) => { - console.log(e); - }); diff --git a/examples/testthing/$DO_NOT_EDIT_JS_FILES.md b/examples/testthing/$DO_NOT_EDIT_JS_FILES.md deleted file mode 100644 index 479e6df00..000000000 --- a/examples/testthing/$DO_NOT_EDIT_JS_FILES.md +++ /dev/null @@ -1,3 +0,0 @@ -# Note - -The JavaScript files in this folder are generated by the workflow described [here](https://github.com/eclipse-thingweb/node-wot/tree/master/packages/examples#workflow). diff --git a/examples/testthing/testclient.js b/examples/testthing/testclient.js deleted file mode 100644 index 772a2368e..000000000 --- a/examples/testthing/testclient.js +++ /dev/null @@ -1,86 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2022 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the W3C Software Notice and - * Document License (2015-05-13) which is available at - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document. - * - * SPDX-License-Identifier: EPL-2.0 OR W3C-20150513 - ********************************************************************************/ - -console.log = () => { - /* empty */ -}; -console.debug = () => { - /* empty */ -}; -async function testPropertyRead(thing, name) { - try { - const res = await thing.readProperty(name); - const value = await res.value(); - console.info("PASS " + name + " READ:", value); - } catch (err) { - console.error("FAIL " + name + " READ:", JSON.stringify(err)); - } -} -async function testPropertyWrite(thing, name, value, shouldFail) { - const displayValue = JSON.stringify(value); - try { - await thing.writeProperty(name, value); - if (!shouldFail) console.info("PASS " + name + " WRITE (" + displayValue + ")"); - else console.error("FAIL " + name + " WRITE: (" + displayValue + ")"); - } catch (err) { - if (!shouldFail) console.error("FAIL " + name + " WRITE (" + displayValue + "):", JSON.stringify(err)); - else console.info("PASS " + name + " WRITE (" + displayValue + "):", JSON.stringify(err)); - } -} -WoT.requestThingDescription("http://localhost:8080/testthing") - .then(async (td) => { - try { - const thing = await WoT.consume(td); - console.info("=== TD ==="); - console.info(td); - console.info("=========="); - console.info(); - console.info("========== bool"); - await testPropertyRead(thing, "bool"); - await testPropertyWrite(thing, "bool", true, false); - await testPropertyWrite(thing, "bool", false, false); - await testPropertyWrite(thing, "bool", "true", true); - console.info("========== int"); - await testPropertyRead(thing, "int"); - await testPropertyWrite(thing, "int", 4711, false); - await testPropertyWrite(thing, "int", 3.1415, true); - await testPropertyWrite(thing, "int", "Pi", true); - console.info("========== num"); - await testPropertyRead(thing, "num"); - await testPropertyWrite(thing, "num", 4711, false); - await testPropertyWrite(thing, "num", 3.1415, false); - await testPropertyWrite(thing, "num", "Pi", true); - console.info("========== string"); - await testPropertyRead(thing, "string"); - await testPropertyWrite(thing, "string", "testclient", false); - await testPropertyWrite(thing, "string", 13, true); - await testPropertyWrite(thing, "string", null, true); - console.info("========== array"); - await testPropertyRead(thing, "array"); - await testPropertyWrite(thing, "array", [23, "illuminated"], false); - await testPropertyWrite(thing, "array", { id: 24, name: "dark" }, true); - await testPropertyWrite(thing, "array", null, true); - console.info("========== object"); - await testPropertyRead(thing, "object"); - await testPropertyWrite(thing, "object", { id: 23, name: "illuminated" }, false); - await testPropertyWrite(thing, "object", null, true); - await testPropertyWrite(thing, "object", [24, "dark"], true); - } catch (err) { - console.error("Script error:", err); - } - }) - .catch((err) => { - console.error("Fetch error:", err); - }); diff --git a/examples/testthing/testthing.js b/examples/testthing/testthing.js deleted file mode 100644 index c2886c22b..000000000 --- a/examples/testthing/testthing.js +++ /dev/null @@ -1,299 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2023 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the W3C Software Notice and - * Document License (2015-05-13) which is available at - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document. - * - * SPDX-License-Identifier: EPL-2.0 OR W3C-20150513 - ********************************************************************************/ -function checkPropertyWrite(expected, actual) { - const output = "Property " + expected + " written with " + actual; - if (expected === actual) { - console.info("PASS: " + output); - } else { - throw new Error("FAIL: " + output); - } -} -function checkActionInvocation(name, expected, actual) { - const output = "Action " + name + " invoked with " + actual; - if (expected === actual) { - console.info("PASS: " + output); - } else { - throw new Error("FAIL: " + output); - } -} -// init property values -let bool = false; -let int = 42; -let num = 3.14; -let string = "unset"; -let array = [2, "unset"]; -let object = { id: 123, name: "abc" }; -WoT.produce({ - title: "TestThing", - properties: { - bool: { - title: "Boolean", - description: "Property that can be set to true or false", - type: "boolean", - }, - int: { - title: "Integer", - description: "An integer value that can be read and written", - type: "integer", - }, - num: { - title: "Number", - description: "A floating point value that can be read and written", - type: "number", - }, - string: { - title: "String", - description: "A string value that can be read and written", - type: "string", - }, - array: { - title: "Array", - description: "An Array (List) with no structure that can be read and written", - type: "array", - items: {}, - }, - object: { - title: "Object", - description: "An object with id and name that can be read and written", - type: "object", - properties: { - id: { - title: "ID", - description: "Integer identifier", - type: "integer", - }, - name: { - title: "Name", - description: "Name associated to the identifier", - type: "string", - }, - }, - }, - }, - actions: { - "void-void": { - title: "void-void Action", - description: "Action without input nor output", - }, - "void-int": { - title: "void-int Action", - description: "Action without input, but with integer output", - }, - "int-void": { - title: "int-void Action", - description: "Action with integer input, but without output", - input: { type: "integer" }, - }, - "int-int": { - title: "int-int Action", - description: "Action with integer input and output", - input: { type: "integer" }, - output: { type: "integer" }, - }, - "int-string": { - title: "int-string Action", - description: "Action with integer input and string output", - input: { type: "integer" }, - output: { type: "string" }, - }, - "void-obj": { - title: "void-obj Action", - description: "Action without input, but with object output", - output: { - type: "object", - properties: { - prop1: { - type: "integer", - }, - prop2: { - type: "string", - }, - }, - required: ["prop1", "prop2"], - }, - }, - "obj-void": { - title: "obj-void Action", - description: "Action with object input, but without output", - input: { - type: "object", - properties: { - prop1: { type: "integer" }, - prop2: { type: "string" }, - }, - required: ["prop1", "prop2"], - }, - }, - }, - events: { - "on-bool": { - title: "Bool Property Change", - description: "Event with boolean data that is emitted when the bool property is written to", - data: { type: "boolean" }, - }, - "on-int": { - title: "Int Property Change", - description: "Event with integer data that is emitted when the int property is written to ", - data: { type: "integer" }, - }, - "on-num": { - title: "Num Property Change", - description: "Event with number data that is emitted when the num property is written to", - data: { type: "number" }, - }, - "on-string": { - title: "String Property Change", - description: "Event with number data that is emitted when the string property is written to", - data: { type: "number" }, - }, - "on-array": { - title: "Array Property Change", - description: "Event with number data that is emitted when the array property is written to", - data: { type: "number" }, - }, - "on-object": { - title: "Object Property Change", - description: "Event with number data that is emitted when the object property is written to", - data: { type: "number" }, - }, - }, -}) - .then((thing) => { - console.log("Produced " + thing.getThingDescription().title); - // set property read/write handlers - thing - .setPropertyWriteHandler("bool", async (value) => { - const localBool = await value.value(); - checkPropertyWrite("boolean", typeof localBool); - bool = localBool; - thing.emitEvent("on-bool", bool); - }) - .setPropertyReadHandler("bool", async () => bool) - .setPropertyWriteHandler("int", async (value) => { - const localInt = await value.value(); - if (localInt === Math.floor(localInt)) { - checkPropertyWrite("integer", "integer"); - } else { - checkPropertyWrite("integer", typeof value); - } - int = localInt; - thing.emitEvent("on-int", int); - }) - .setPropertyReadHandler("int", async () => int) - .setPropertyWriteHandler("num", async (value) => { - const localNum = await value.value(); - checkPropertyWrite("number", typeof localNum); - num = localNum; - thing.emitEvent("on-num", num); - }) - .setPropertyReadHandler("num", async () => num) - .setPropertyWriteHandler("string", async (value) => { - const localString = await value.value(); - checkPropertyWrite("string", typeof localString); - string = localString; - thing.emitEvent("on-string", string); - }) - .setPropertyReadHandler("string", async () => string) - .setPropertyWriteHandler("array", async (value) => { - const localArray = await value.value(); - if (Array.isArray(localArray)) { - checkPropertyWrite("array", "array"); - } else { - checkPropertyWrite("array", typeof localArray); - } - array = localArray; - thing.emitEvent("on-array", array); - }) - .setPropertyReadHandler("array", async () => array) - .setPropertyWriteHandler("object", async (value) => { - const localObject = await value.value(); - if (Array.isArray(localObject)) { - checkPropertyWrite("object", "array"); - } else { - checkPropertyWrite("object", typeof localObject); - } - object = localObject; - thing.emitEvent("on-object", object); - }) - .setPropertyReadHandler("object", async () => object); - // set action handlers - thing - .setActionHandler("void-void", async (parameters) => { - checkActionInvocation("void-void", "undefined", typeof (await parameters.value())); - return undefined; - }) - .setActionHandler("void-int", async (parameters) => { - checkActionInvocation("void-int", "undefined", typeof (await parameters.value())); - return 0; - }) - .setActionHandler("int-void", async (parameters) => { - const localParameters = await parameters.value(); - if (localParameters === Math.floor(localParameters)) { - checkActionInvocation("int-void", "integer", "integer"); - } else { - checkActionInvocation("int-void", "integer", typeof parameters); - } - return undefined; - }) - .setActionHandler("int-int", async (parameters) => { - const localParameters = await parameters.value(); - if (localParameters === Math.floor(localParameters)) { - checkActionInvocation("int-int", "integer", "integer"); - } else { - checkActionInvocation("int-int", "integer", typeof localParameters); - } - return localParameters + 1; - }) - .setActionHandler("int-string", async (parameters) => { - const localParameters = await parameters.value(); - const inputtype = typeof localParameters; - if (localParameters === Math.floor(localParameters)) { - checkActionInvocation("int-string", "integer", "integer"); - } else { - checkActionInvocation("int-string", "integer", typeof localParameters); - } - if (inputtype === "number") { - // eslint-disable-next-line no-new-wrappers - return new String(localParameters) - .replace(/0/g, "zero-") - .replace(/1/g, "one-") - .replace(/2/g, "two-") - .replace(/3/g, "three-") - .replace(/4/g, "four-") - .replace(/5/g, "five-") - .replace(/6/g, "six-") - .replace(/7/g, "seven-") - .replace(/8/g, "eight-") - .replace(/9/g, "nine-"); - } else { - throw new Error("ERROR"); - } - }) - .setActionHandler("void-obj", async (parameters) => { - checkActionInvocation("void-complex", "undefined", typeof (await parameters.value())); - return { prop1: 123, prop2: "abc" }; - }) - .setActionHandler("obj-void", async (parameters) => { - checkActionInvocation("complex-void", "object", typeof (await parameters.value())); - return undefined; - }); - // expose the thing - thing.expose().then(() => { - console.info(thing.getThingDescription().title + " ready"); - }); - }) - .catch((e) => { - console.log(e); - }); diff --git a/packages/binding-modbus/testConsumer.js b/packages/binding-modbus/testConsumer.js new file mode 100644 index 000000000..f4896cf06 --- /dev/null +++ b/packages/binding-modbus/testConsumer.js @@ -0,0 +1,124 @@ +/******************************************************************************** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the W3C Software Notice and + * Document License (2015-05-13) which is available at + * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document. + * + * SPDX-License-Identifier: EPL-2.0 OR W3C-20150513 + ********************************************************************************/ +const fs = require("fs"); // to read JSON file in AID format +// Protocols and Servient +Servient = require("@node-wot/core").Servient; +ModbusClientFactory = require("@node-wot/binding-modbus").ModbusClientFactory; + +// create Servient and add Modbus binding +let servient = new Servient(); +servient.addClientFactory(new ModbusClientFactory()); + +async function main() { + let td = { + "@context": [ + "https://www.w3.org/2019/wot/td/v1", + "https://www.w3.org/2022/wot/td/v1.1", + { + "@language": "en", + }, + ], + "@type": "Thing", + title: "modbus-elevator", + description: "Elevator Thing", + securityDefinitions: { + nosec_sc: { + scheme: "nosec", + }, + }, + security: ["nosec_sc"], + base: "modbus+tcp://0.0.0.0:3179/1/", + properties: { + lightSwitch: { + type: "boolean", + readOnly: false, + writeOnly: false, + observable: false, + forms: [ + { + href: "1?quantity=1", + op: "readproperty", + "modv:entity": "Coil", + "modv:function": "readCoil", + contentType: "application/octet-stream", + }, + { + href: "1?quantity=1", + op: "writeproperty", + "modv:entity": "Coil", + "modv:function": "writeSingleCoil", + contentType: "application/octet-stream", + }, + ], + }, + onTheMove: { + type: "boolean", + readOnly: true, + writeOnly: false, + observable: true, + forms: [ + { + href: "1&quantity=1", + op: ["readproperty", "observeproperty"], + "modv:entity": "DiscreteInput", + "modv:function": "readDiscreteInput", + "modv:pollingTime": 1000, + contentType: "application/octet-stream", + }, + ], + }, + floorNumber: { + type: "integer", + minimum: 0, + maximum: 15, + readOnly: false, + writeOnly: false, + observable: false, + forms: [ + { + href: "1?quantity=1", + op: "readproperty", + "modv:entity": "HoldingRegister", + "modv:function": "readHoldingRegisters", + contentType: "application/octet-stream;length=2;byteSeq=BIG_ENDIAN", + }, + { + href: "1?quantity=1", + op: "writeproperty", + "modv:entity": "HoldingRegister", + "modv:function": "writeSingleHoldingRegister", + contentType: "application/octet-stream", + }, + ], + }, + }, + }; + + const WoT = await servient.start(); + const thing = await WoT.consume(td); + + // console.log(JSON.stringify(thing.getThingDescription())) + + const readData1 = await thing.readProperty("lightSwitch"); //coil + const readData2 = await thing.readProperty("floorNumber"); //register + + const readValue1 = await readData1.value(); + console.log(readValue1); + + const readValue2 = await readData2.value(); + console.log(readValue2); +} + +main(); diff --git a/packages/examples/src/quickstart/README.md b/packages/examples/src/quickstart/README.md deleted file mode 100644 index 0183dad5f..000000000 --- a/packages/examples/src/quickstart/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Quick Start Things - -This set of Things can be used to build mashup applications for a smart home scenario. -These Things are: - -- Simple coffee machine that can take an order to brew a coffee. -- Presence sensor that emits an event when a person is detected. -- Smart clock that runs 60 times faster than real time, where 1 hour happens in 1 minute. - -These Things are hosted on plugfest.thingweb.io but can be also self-hosted. diff --git a/packages/examples/src/quickstart/presence-sensor.ts b/packages/examples/src/quickstart/presence-sensor.ts deleted file mode 100644 index cb6614e01..000000000 --- a/packages/examples/src/quickstart/presence-sensor.ts +++ /dev/null @@ -1,64 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2023 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the W3C Software Notice and - * Document License (2015-05-13) which is available at - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document. - * - * SPDX-License-Identifier: EPL-2.0 OR W3C-20150513 - ********************************************************************************/ - -// This is an example Thing script which is a simple presence detector -// It fires an event when it detects a person (mocked as every 5 second) - -import { Servient } from "@node-wot/core"; -import { MqttBrokerServer } from "@node-wot/binding-mqtt"; - -// create Servient add MQTT binding with port configuration -const servient = new Servient(); -servient.addServer(new MqttBrokerServer({ uri: "mqtt://test.mosquitto.org" })); - -servient.start().then((WoT) => { - WoT.produce({ - title: "PresenceSensor", - description: "Thing that can detect presence of human nearby", - support: "https://github.com/eclipse-thingweb/node-wot/", - "@context": "https://www.w3.org/2022/wot/td/v1.1", - events: { - presenceDetected: { - title: "Presence Detected", - description: - "An event that is emitted when a person is detected in the room. It is mocked and emitted every 5 seconds", - data: { - type: "number", - title: "Distance", - minimum: 55, - maximum: 1200, - }, - }, - }, - }) - .then((thing) => { - console.log("Produced " + thing.getThingDescription().title); - - // expose the thing - thing.expose().then(() => { - console.info(thing.getThingDescription().title + " ready"); - - // mocking the detection with an event sent every 5 seconds, with a random distance - setInterval(() => { - const distance: number = Math.random() * (1200 - 55) + 55; - thing.emitEvent("presenceDetected", distance); - console.info("Emitted presence with distance ", distance); - }, 5000); - }); - }) - .catch((e) => { - console.log(e); - }); -}); diff --git a/packages/examples/src/quickstart/simple-coffee-machine.ts b/packages/examples/src/quickstart/simple-coffee-machine.ts deleted file mode 100644 index 69fdc7c2f..000000000 --- a/packages/examples/src/quickstart/simple-coffee-machine.ts +++ /dev/null @@ -1,213 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2023 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the W3C Software Notice and - * Document License (2015-05-13) which is available at - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document. - * - * SPDX-License-Identifier: EPL-2.0 OR W3C-20150513 - ********************************************************************************/ - -// This is an example Thing script which is a simple coffee machine. -// You can order coffee and see the status of the resources - -import { Servient, Helpers } from "@node-wot/core"; -import { HttpServer } from "@node-wot/binding-http"; - -// create Servient add HTTP binding with port configuration -const servient = new Servient(); - -// const staticAddress = "plugfest.thingweb.io"; -const staticAddress = "localhost"; // use this for testing locally -const httpPort = 8081; -servient.addServer( - new HttpServer({ - port: httpPort, - }) -); -Helpers.setStaticAddress(staticAddress); - -let waterAmount = 1000; -let beansAmount = 1000; -let milkAmount = 1000; - -// promisify timeout since it does not return a promise -function timeout(ms: number) { - return new Promise((resolve) => setTimeout(resolve, ms)); -} - -servient.start().then((WoT) => { - WoT.produce({ - title: "Coffee Machine", - description: "A simple coffee machine that can be interacted over the Internet", - support: "https://github.com/eclipse-thingweb/node-wot/", - "@context": "https://www.w3.org/2022/wot/td/v1.1", - properties: { - resources: { - readOnly: true, - observable: true, - type: "object", - properties: { - water: { - type: "integer", - minimum: 0, - maximum: 1000, - }, - beans: { - type: "integer", - minimum: 0, - maximum: 1000, - }, - milk: { - type: "integer", - minimum: 0, - maximum: 1000, - }, - }, - }, - }, - actions: { - brew: { - synchronous: true, - input: { - type: "string", - enum: ["espresso", "cappuccino", "americano"], - }, - }, - refill: { - synchronous: true, - input: { - type: "array", - items: { - type: "string", - enum: ["water", "beans", "milk"], - }, - }, - }, - }, - events: { - resourceEmpty: { - data: { - type: "array", - items: { - type: "string", - enum: ["water", "beans", "milk"], - }, - }, - }, - }, - }) - .then((thing) => { - console.log("Produced " + thing.getThingDescription().title); - - thing.setPropertyReadHandler("resources", async () => { - return { - water: waterAmount, - beans: beansAmount, - milk: milkAmount, - }; - }); - - thing.setActionHandler("brew", async (params, options) => { - const coffeeType = await params.value(); - console.info("received coffee order of ", coffeeType); - if (coffeeType === "espresso") { - if (waterAmount <= 10 || beansAmount <= 10) { - throw new Error("Not enough water or beans"); - } else { - await timeout(1000); - waterAmount = waterAmount - 10; - beansAmount = beansAmount - 10; - thing.emitPropertyChange("resources"); - const resourceEvent: Array = []; - if (waterAmount <= 10) { - resourceEvent.push("water"); - } - if (beansAmount <= 10) { - resourceEvent.push("beans"); - } - if (resourceEvent.length > 0) { - thing.emitEvent("resourceEmpty", resourceEvent); - } - return undefined; - } - } else if (coffeeType === "cappuccino") { - if (waterAmount <= 20 || beansAmount <= 25 || milkAmount <= 15) { - throw new Error("Not enough water or beans"); - } else { - await timeout(2000); - waterAmount = waterAmount - 15; - beansAmount = beansAmount - 20; - milkAmount = milkAmount - 10; - thing.emitPropertyChange("resources"); - const resourceEvent: Array = []; - if (waterAmount <= 10) { - resourceEvent.push("water"); - } - if (beansAmount <= 10) { - resourceEvent.push("beans"); - } - if (milkAmount <= 10) { - resourceEvent.push("milk"); - } - if (resourceEvent.length > 0) { - thing.emitEvent("resourceEmpty", resourceEvent); - } - return undefined; - } - } else if (coffeeType === "americano") { - if (waterAmount <= 35 || beansAmount <= 10) { - throw new Error("Not enough water or beans"); - } else { - await timeout(2000); - waterAmount = waterAmount - 30; - beansAmount = beansAmount - 10; - thing.emitPropertyChange("resources"); - const resourceEvent: Array = []; - if (waterAmount <= 10) { - resourceEvent.push("water"); - } - if (beansAmount <= 10) { - resourceEvent.push("beans"); - } - if (resourceEvent.length > 0) { - thing.emitEvent("resourceEmpty", resourceEvent); - } - return undefined; - } - } else { - throw new Error("Wrong coffee input"); - } - }); - - thing.setActionHandler("refill", async (params, options) => { - const selectedResource = (await params.value()) as Array<"water" | "beans" | "milk">; - console.info("received refill order of ", selectedResource); - if (selectedResource!.indexOf("water") !== -1) { - waterAmount = 1000; - } - if (selectedResource!.indexOf("beans") !== -1) { - beansAmount = 1000; - } - if (selectedResource!.indexOf("milk") !== -1) { - milkAmount = 1000; - } - thing.emitPropertyChange("resources"); - return undefined; - }); - - // expose the thing - thing.expose().then(() => { - console.info(thing.getThingDescription().title + " ready"); - console.info("TD available at http://" + staticAddress + ":" + httpPort); - }); - }) - .catch((e) => { - console.log(e); - }); -}); diff --git a/packages/examples/src/quickstart/smart-clock.ts b/packages/examples/src/quickstart/smart-clock.ts deleted file mode 100644 index 2043dbcb1..000000000 --- a/packages/examples/src/quickstart/smart-clock.ts +++ /dev/null @@ -1,97 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2023 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the W3C Software Notice and - * Document License (2015-05-13) which is available at - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document. - * - * SPDX-License-Identifier: EPL-2.0 OR W3C-20150513 - ********************************************************************************/ - -// This is an example Thing which is a smart clock that runs 60 times faster than real time, where 1 hour happens in 1 minute. - -import { Servient, Helpers } from "@node-wot/core"; -import { CoapServer } from "@node-wot/binding-coap"; - -// create Servient add CoAP binding with port configuration -const servient = new Servient(); -servient.addServer(new CoapServer({ port: 5686 })); - -Helpers.setStaticAddress("plugfest.thingweb.io"); // comment this out if you are testing locally - -let minuteCounter = 0; -let hourCounter = 0; - -async function timeCount(thing: WoT.ExposedThing) { - for (minuteCounter = 0; minuteCounter < 59; minuteCounter++) { - // if we have <60, we can get a 15:60. - await new Promise((resolve) => setTimeout(resolve, 1000)); // sleep - thing.emitPropertyChange("time"); - } - console.info({ - hour: hourCounter, - minute: minuteCounter, - }); - - hourCounter++; - if (hourCounter === 24) { - hourCounter = 0; - } -} - -servient.start().then((WoT) => { - WoT.produce({ - title: "Smart Clock", - description: "a smart clock that runs 60 times faster than real time, where 1 hour happens in 1 minute.", - support: "https://github.com/eclipse-thingweb/node-wot/", - "@context": "https://www.w3.org/2022/wot/td/v1.1", - properties: { - time: { - readOnly: true, - observable: true, - type: "object", - properties: { - minute: { - type: "integer", - minimum: 0, - maximum: 59, - }, - hour: { - type: "integer", - minimum: 0, - maximum: 23, - }, - }, - }, - }, - }) - .then(async (thing) => { - console.log("Produced " + thing.getThingDescription().title); - - thing.setPropertyReadHandler("time", async () => { - return { - hour: hourCounter, - minute: minuteCounter, - }; - }); - - timeCount(thing); - setInterval(async () => { - timeCount(thing); - thing.emitPropertyChange("time"); - }, 61000); // if this is 60s, we never leave the for loop - - // expose the thing - thing.expose().then(() => { - console.info(thing.getThingDescription().title + " ready"); - }); - }) - .catch((e) => { - console.log(e); - }); -}); diff --git a/packages/examples/src/scripts/smart-coffee-machine-client.ts b/packages/examples/src/scripts/smart-coffee-machine-client.ts deleted file mode 100644 index ab81b579b..000000000 --- a/packages/examples/src/scripts/smart-coffee-machine-client.ts +++ /dev/null @@ -1,97 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2020 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the W3C Software Notice and - * Document License (2015-05-13) which is available at - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document. - * - * SPDX-License-Identifier: EPL-2.0 OR W3C-20150513 - ********************************************************************************/ - -// This is an example of Web of Things consumer ("client" mode) Thing script. -// It considers a fictional smart coffee machine in order to demonstrate the capabilities of Web of Things. -// An accompanying tutorial is available at http://www.thingweb.io/smart-coffee-machine.html. - -// Print data and an accompanying message in a distinguishable way -function log(msg: string, data: unknown) { - console.info("======================"); - console.info(msg); - console.dir(data); - console.info("======================"); -} - -WoT.requestThingDescription("http://127.0.0.1:8080/smart-coffee-machine").then(async (td) => { - try { - const thing = await WoT.consume(td); - log("Thing Description:", td); - - // Read property allAvailableResources - let allAvailableResources = await (await thing.readProperty("allAvailableResources")).value(); - log("allAvailableResources value is:", allAvailableResources); - - // Now let's change water level to 80 - await thing.writeProperty("availableResourceLevel", 80, { uriVariables: { id: "water" } }); - - // And see that the water level has changed - const waterLevel = await ( - await thing.readProperty("availableResourceLevel", { uriVariables: { id: "water" } }) - ).value(); - log("waterLevel value after change is:", waterLevel); - - // This can also be seen in allAvailableResources property - allAvailableResources = await (await thing.readProperty("allAvailableResources")).value(); - log("allAvailableResources value after change is:", allAvailableResources); - - // It's also possible to set a client-side handler for observable properties - thing.observeProperty("maintenanceNeeded", async (data) => { - log("maintenanceNeeded property has changed! New value is:", await data.value()); - }); - - // Now let's make 3 cups of latte! - const makeCoffee = await thing.invokeAction("makeDrink", undefined, { - uriVariables: { drinkId: "latte", size: "l", quantity: 3 }, - }); - const makeCoffeep = (await makeCoffee?.value()) as Record; - if (makeCoffeep.result != null) { - log("Enjoy your drink!", makeCoffeep); - } else { - log("Failed making your drink:", makeCoffeep); - } - - // See how allAvailableResources property value has changed - allAvailableResources = await (await thing.readProperty("allAvailableResources")).value(); - log("allAvailableResources value is:", allAvailableResources); - - // Let's add a scheduled task - const scheduledTask = await thing.invokeAction("setSchedule", { - drinkId: "espresso", - size: "m", - quantity: 2, - time: "10:00", - mode: "everyday", - }); - const scheduledTaskp = (await scheduledTask?.value()) as Record; - log(scheduledTaskp.message, scheduledTaskp); - - // See how it has been added to the schedules property - const schedules = await (await thing.readProperty("schedules")).value(); - log("schedules value: ", schedules); - - // Let's set up a handler for outOfResource event - thing.subscribeEvent("outOfResource", async (data) => { - // Here we are simply logging the message when the event is emitted - // But, of course, could have a much more sophisticated handler - log("outOfResource event:", await data.value()); - }); - - // fire property change for maintenanceNeeded - await thing.writeProperty("servedCounter", 1001); - } catch (err) { - console.error("Script error:", err); - } -}); diff --git a/packages/examples/src/scripts/smart-coffee-machine.ts b/packages/examples/src/scripts/smart-coffee-machine.ts deleted file mode 100644 index 977b1693a..000000000 --- a/packages/examples/src/scripts/smart-coffee-machine.ts +++ /dev/null @@ -1,420 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2020 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the W3C Software Notice and - * Document License (2015-05-13) which is available at - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document. - * - * SPDX-License-Identifier: EPL-2.0 OR W3C-20150513 - ********************************************************************************/ - -// This is an example of Web of Things producer ("server" mode) Thing script. -// It considers a fictional smart coffee machine in order to demonstrate the capabilities of Web of Things. -// An accompanying tutorial is available at http://www.thingweb.io/smart-coffee-machine.html. - -let allAvailableResources: Record; -let possibleDrinks: string[]; -let maintenanceNeeded: boolean; -let schedules: unknown[]; -let servedCounter: number; - -function readFromSensor(sensorType: string): number { - // Actual implementation of reading data from a sensor can go here - // For the sake of example, let's just return a value - return 100; -} - -function notify(subscribers: unknown, msg: string) { - // Actual implementation of notifying subscribers with a message can go here - console.log(msg); -} - -WoT.produce({ - title: "Smart-Coffee-Machine", - description: `A smart coffee machine with a range of capabilities. -A complementary tutorial is available at http://www.thingweb.io/smart-coffee-machine.html.`, - support: "https://github.com/eclipse-thingweb/node-wot/", - properties: { - allAvailableResources: { - type: "object", - description: `Current level of all available resources given as an integer percentage for each particular resource. -The data is obtained from the machine's sensors but can be set manually via the availableResourceLevel property in case the sensors are broken.`, - readOnly: true, - properties: { - water: { - type: "integer", - minimum: 0, - maximum: 100, - }, - milk: { - type: "integer", - minimum: 0, - maximum: 100, - }, - chocolate: { - type: "integer", - minimum: 0, - maximum: 100, - }, - coffeeBeans: { - type: "integer", - minimum: 0, - maximum: 100, - }, - }, - }, - availableResourceLevel: { - type: "number", - description: `Current level of a particular resource. Requires resource id variable as uriVariables. -The property can also be overridden, which also requires resource id as uriVariables.`, - uriVariables: { - id: { - type: "string", - enum: ["water", "milk", "chocolate", "coffeeBeans"], - }, - }, - }, - possibleDrinks: { - type: "array", - description: `The list of possible drinks in general. Doesn't depend on the available resources.`, - readOnly: true, - items: { - type: "string", - }, - }, - servedCounter: { - type: "integer", - description: `The total number of served beverages.`, - minimum: 0, - }, - maintenanceNeeded: { - type: "boolean", - description: `Shows whether a maintenance is needed. The property is observable. Automatically set to true when the servedCounter property exceeds 1000.`, - observable: true, - }, - schedules: { - type: "array", - description: `The list of scheduled tasks.`, - readOnly: true, - items: { - type: "object", - properties: { - drinkId: { - type: "string", - description: `Defines what drink to make, drinkId is one of possibleDrinks property values, e.g. latte.`, - }, - size: { - type: "string", - description: `Defines the size of a drink, s = small, m = medium, l = large.`, - enum: ["s", "m", "l"], - }, - quantity: { - type: "integer", - description: `Defines how many drinks to make, ranging from 1 to 5.`, - minimum: 1, - maximum: 5, - }, - time: { - type: "string", - description: `Defines the time of the scheduled task in 24h format, e.g. 10:00 or 21:00.`, - }, - mode: { - type: "string", - description: `Defines the mode of the scheduled task, e.g. once or everyday. All the possible values are given in the enum field of this Thing Description.`, - enum: [ - "once", - "everyday", - "everyMo", - "everyTu", - "everyWe", - "everyTh", - "everyFr", - "everySat", - "everySun", - ], - }, - }, - }, - }, - }, - actions: { - makeDrink: { - description: `Make a drink from available list of beverages. Accepts drink id, size and quantity as uriVariables. -Brews one medium americano if no uriVariables are specified.`, - uriVariables: { - drinkId: { - type: "string", - description: `Defines what drink to make, drinkId is one of possibleDrinks property values, e.g. latte.`, - }, - size: { - type: "string", - description: `Defines the size of a drink, s = small, m = medium, l = large.`, - enum: ["s", "m", "l"], - }, - quantity: { - type: "integer", - description: `Defines how many drinks to make, ranging from 1 to 5.`, - minimum: 1, - maximum: 5, - }, - }, - output: { - type: "object", - description: `Returns true/false and a message when all invoked promises are resolved (asynchronous).`, - properties: { - result: { - type: "boolean", - }, - message: { - type: "string", - }, - }, - }, - }, - setSchedule: { - description: `Add a scheduled task to the schedules property. Accepts drink id, size, quantity, time and mode as body of a request. -Assumes one medium americano if not specified, but time and mode are mandatory fields.`, - input: { - type: "object", - properties: { - drinkId: { - type: "string", - description: `Defines what drink to make, drinkId is one of possibleDrinks property values, e.g. latte.`, - }, - size: { - type: "string", - description: `Defines the size of a drink, s = small, m = medium, l = large.`, - enum: ["s", "m", "l"], - }, - quantity: { - type: "integer", - description: `Defines how many drinks to make, ranging from 1 to 5.`, - minimum: 1, - maximum: 5, - }, - time: { - type: "string", - description: `Defines the time of the scheduled task in 24h format, e.g. 10:00 or 21:00.`, - }, - mode: { - type: "string", - description: `Defines the mode of the scheduled task, e.g. once or everyday. All the possible values are given in the enum field of this Thing Description.`, - enum: [ - "once", - "everyday", - "everyMo", - "everyTu", - "everyWe", - "everyTh", - "everyFr", - "everySat", - "everySun", - ], - }, - }, - required: ["time", "mode"], - }, - output: { - type: "object", - description: `Returns true/false and a message when all invoked promises are resolved (asynchronous).`, - properties: { - result: { - type: "boolean", - }, - message: { - type: "string", - }, - }, - }, - }, - }, - events: { - outOfResource: { - description: `Out of resource event. Emitted when the available resource level is not sufficient for a desired drink.`, - data: { - type: "string", - }, - }, - }, -}) - .then((thing) => { - // Initialize the property values - allAvailableResources = { - water: readFromSensor("water"), - milk: readFromSensor("milk"), - chocolate: readFromSensor("chocolate"), - coffeeBeans: readFromSensor("coffeeBeans"), - }; - possibleDrinks = ["espresso", "americano", "cappuccino", "latte", "hotChocolate", "hotWater"]; - maintenanceNeeded = false; - schedules = []; - - thing.setPropertyReadHandler("allAvailableResources", async () => allAvailableResources); - thing.setPropertyReadHandler("possibleDrinks", async () => possibleDrinks); - thing.setPropertyReadHandler("maintenanceNeeded", async () => maintenanceNeeded); - thing.setPropertyReadHandler("schedules", async () => schedules); - - // Override a write handler for servedCounter property, - // raising maintenanceNeeded flag when the value exceeds 1000 drinks - thing.setPropertyWriteHandler("servedCounter", async (val) => { - servedCounter = (await val.value()) as number; - if (servedCounter > 1000) { - maintenanceNeeded = true; - thing.emitPropertyChange("maintenanceNeeded"); - - // Notify a "maintainer" when the value has changed - // (the notify function here simply logs a message to the console) - notify( - "admin@coffeeMachine.com", - `maintenanceNeeded property has changed, new value is: ${maintenanceNeeded}` - ); - } - }); - - // Now initialize the servedCounter property - servedCounter = readFromSensor("servedCounter"); - - // Override a write handler for availableResourceLevel property, - // utilizing the uriVariables properly - thing.setPropertyWriteHandler("availableResourceLevel", async (val, options) => { - // Check if uriVariables are provided - if (options && typeof options === "object" && "uriVariables" in options) { - const uriVariables = options.uriVariables as Record; - if ("id" in uriVariables) { - const id = uriVariables.id; - allAvailableResources[id] = (await val.value()) as number; - return; - } - } - throw Error("Please specify id variable as uriVariables."); - }); - - // Override a read handler for availableResourceLevel property, - // utilizing the uriVariables properly - thing.setPropertyReadHandler("availableResourceLevel", async (options) => { - // Check if uriVariables are provided - if (options && typeof options === "object" && "uriVariables" in options) { - const uriVariables = options.uriVariables as Record; - if ("id" in uriVariables) { - const id = uriVariables.id; - return allAvailableResources[id]; - } - } - throw Error("Please specify id variable as uriVariables."); - }); - - // Set up a handler for makeDrink action - thing.setActionHandler("makeDrink", async (_params, options) => { - // Default values - let drinkId = "americano"; - let size = "m"; - let quantity = 1; - - // Size quantifiers - const sizeQuantifiers: Record = { s: 0.1, m: 0.2, l: 0.3 }; - - // Drink recipes showing the amount of a resource consumed for a particular drink - const drinkRecipes: Record> = { - espresso: { - water: 1, - milk: 0, - chocolate: 0, - coffeeBeans: 2, - }, - americano: { - water: 2, - milk: 0, - chocolate: 0, - coffeeBeans: 2, - }, - cappuccino: { - water: 1, - milk: 1, - chocolate: 0, - coffeeBeans: 2, - }, - latte: { - water: 1, - milk: 2, - chocolate: 0, - coffeeBeans: 2, - }, - hotChocolate: { - water: 0, - milk: 0, - chocolate: 1, - coffeeBeans: 0, - }, - hotWater: { - water: 1, - milk: 0, - chocolate: 0, - coffeeBeans: 0, - }, - }; - - // Check if uriVariables are provided - if (options && typeof options === "object" && "uriVariables" in options) { - const uriVariables = options.uriVariables as Record; - drinkId = "drinkId" in uriVariables ? (uriVariables.drinkId as string) : drinkId; - size = "size" in uriVariables ? (uriVariables.size as string) : size; - quantity = "quantity" in uriVariables ? (uriVariables.quantity as number) : quantity; - } - - // Calculate the new level of resources - const newResources = Object.assign({}, allAvailableResources); - newResources.water -= Math.ceil(quantity * sizeQuantifiers[size] * drinkRecipes[drinkId].water); - newResources.milk -= Math.ceil(quantity * sizeQuantifiers[size] * drinkRecipes[drinkId].milk); - newResources.chocolate -= Math.ceil(quantity * sizeQuantifiers[size] * drinkRecipes[drinkId].chocolate); - newResources.coffeeBeans -= Math.ceil(quantity * sizeQuantifiers[size] * drinkRecipes[drinkId].coffeeBeans); - - // Check if the amount of available resources is sufficient to make a drink - for (const resource in newResources) { - if (newResources[resource] <= 0) { - thing.emitEvent("outOfResource", `Low level of ${resource}: ${newResources[resource]}%`); - return { result: false, message: `${resource} level is not sufficient` }; - } - } - - // Now store the new level of allAvailableResources - allAvailableResources = newResources; - servedCounter = servedCounter + quantity; - - // Finally deliver the drink - return { result: true, message: `Your ${drinkId} is in progress!` }; - }); - - // Set up a handler for setSchedule action - thing.setActionHandler("setSchedule", async (params, options) => { - const paramsp = (await params.value()) as Record; // : any = await Helpers.parseInteractionOutput(params); - - // Check if uriVariables are provided - if (paramsp != null && typeof paramsp === "object" && "time" in paramsp && "mode" in paramsp) { - // Use default values if not provided - paramsp.drinkId = "drinkId" in paramsp ? paramsp.drinkId : "americano"; - paramsp.size = "size" in paramsp ? paramsp.size : "m"; - paramsp.quantity = "quantity" in paramsp ? paramsp.quantity : 1; - - // Now add a new schedule - schedules.push(paramsp); - - return { result: true, message: `Your schedule has been set!` }; - } - - return { result: false, message: `Please provide all the required parameters: time and mode.` }; - }); - - // Finally expose the thing - thing.expose().then(() => { - console.info(`${thing.getThingDescription().title} ready`); - }); - console.log(`Produced ${thing.getThingDescription().title}`); - }) - .catch((e) => { - console.log(e); - }); diff --git a/packages/examples/src/testthing/testclient.ts b/packages/examples/src/testthing/testclient.ts deleted file mode 100644 index 672c387f2..000000000 --- a/packages/examples/src/testthing/testclient.ts +++ /dev/null @@ -1,100 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2020 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the W3C Software Notice and - * Document License (2015-05-13) which is available at - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document. - * - * SPDX-License-Identifier: EPL-2.0 OR W3C-20150513 - ********************************************************************************/ - -console.log = () => { - /* empty */ -}; -console.debug = () => { - /* empty */ -}; - -async function testPropertyRead(thing: WoT.ConsumedThing, name: string) { - try { - const res = await thing.readProperty(name); - const value = await res.value(); - console.info("PASS " + name + " READ:", value); - } catch (err) { - console.error("FAIL " + name + " READ:", JSON.stringify(err)); - } -} - -async function testPropertyWrite( - thing: WoT.ConsumedThing, - name: string, - value: WoT.InteractionInput, - shouldFail: boolean -) { - const displayValue = JSON.stringify(value); - try { - await thing.writeProperty(name, value); - if (!shouldFail) console.info("PASS " + name + " WRITE (" + displayValue + ")"); - else console.error("FAIL " + name + " WRITE: (" + displayValue + ")"); - } catch (err) { - if (!shouldFail) console.error("FAIL " + name + " WRITE (" + displayValue + "):", JSON.stringify(err)); - else console.info("PASS " + name + " WRITE (" + displayValue + "):", JSON.stringify(err)); - } -} - -WoT.requestThingDescription("http://localhost:8080/testthing") - .then(async (td) => { - try { - const thing = await WoT.consume(td); - console.info("=== TD ==="); - console.info(td); - console.info("=========="); - console.info(); - - console.info("========== bool"); - await testPropertyRead(thing, "bool"); - await testPropertyWrite(thing, "bool", true, false); - await testPropertyWrite(thing, "bool", false, false); - await testPropertyWrite(thing, "bool", "true", true); - - console.info("========== int"); - await testPropertyRead(thing, "int"); - await testPropertyWrite(thing, "int", 4711, false); - await testPropertyWrite(thing, "int", 3.1415, true); - await testPropertyWrite(thing, "int", "Pi", true); - - console.info("========== num"); - await testPropertyRead(thing, "num"); - await testPropertyWrite(thing, "num", 4711, false); - await testPropertyWrite(thing, "num", 3.1415, false); - await testPropertyWrite(thing, "num", "Pi", true); - - console.info("========== string"); - await testPropertyRead(thing, "string"); - await testPropertyWrite(thing, "string", "testclient", false); - await testPropertyWrite(thing, "string", 13, true); - await testPropertyWrite(thing, "string", null, true); - - console.info("========== array"); - await testPropertyRead(thing, "array"); - await testPropertyWrite(thing, "array", [23, "illuminated"], false); - await testPropertyWrite(thing, "array", { id: 24, name: "dark" }, true); - await testPropertyWrite(thing, "array", null, true); - - console.info("========== object"); - await testPropertyRead(thing, "object"); - await testPropertyWrite(thing, "object", { id: 23, name: "illuminated" }, false); - await testPropertyWrite(thing, "object", null, true); - await testPropertyWrite(thing, "object", [24, "dark"], true); - } catch (err) { - console.error("Script error:", err); - } - }) - .catch((err) => { - console.error("Fetch error:", err); - }); diff --git a/packages/examples/src/testthing/testthing.ts b/packages/examples/src/testthing/testthing.ts deleted file mode 100644 index 4590ee58b..000000000 --- a/packages/examples/src/testthing/testthing.ts +++ /dev/null @@ -1,307 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2020 Contributors to the Eclipse Foundation - * - * See the NOTICE file(s) distributed with this work for additional - * information regarding copyright ownership. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, or the W3C Software Notice and - * Document License (2015-05-13) which is available at - * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document. - * - * SPDX-License-Identifier: EPL-2.0 OR W3C-20150513 - ********************************************************************************/ - -function checkPropertyWrite(expected: string, actual: unknown) { - const output = "Property " + expected + " written with " + actual; - if (expected === actual) { - console.info("PASS: " + output); - } else { - throw new Error("FAIL: " + output); - } -} - -function checkActionInvocation(name: string, expected: string, actual: unknown) { - const output = "Action " + name + " invoked with " + actual; - if (expected === actual) { - console.info("PASS: " + output); - } else { - throw new Error("FAIL: " + output); - } -} - -// init property values -let bool = false; -let int = 42; -let num = 3.14; -let string = "unset"; -let array: unknown[] = [2, "unset"]; -let object: Record = { id: 123, name: "abc" }; - -WoT.produce({ - title: "TestThing", - properties: { - bool: { - title: "Boolean", - description: "Property that can be set to true or false", - type: "boolean", - }, - int: { - title: "Integer", - description: "An integer value that can be read and written", - type: "integer", - }, - num: { - title: "Number", - description: "A floating point value that can be read and written", - type: "number", - }, - string: { - title: "String", - description: "A string value that can be read and written", - type: "string", - }, - array: { - title: "Array", - description: "An Array (List) with no structure that can be read and written", - type: "array", - items: {}, - }, - object: { - title: "Object", - description: "An object with id and name that can be read and written", - type: "object", - properties: { - id: { - title: "ID", - description: "Integer identifier", - type: "integer", - }, - name: { - title: "Name", - description: "Name associated to the identifier", - type: "string", - }, - }, - }, - }, - actions: { - "void-void": { - title: "void-void Action", - description: "Action without input nor output", - }, - "void-int": { - title: "void-int Action", - description: "Action without input, but with integer output", - }, - "int-void": { - title: "int-void Action", - description: "Action with integer input, but without output", - input: { type: "integer" }, - }, - "int-int": { - title: "int-int Action", - description: "Action with integer input and output", - input: { type: "integer" }, - output: { type: "integer" }, - }, - "int-string": { - title: "int-string Action", - description: "Action with integer input and string output", - input: { type: "integer" }, - output: { type: "string" }, - }, - "void-obj": { - title: "void-obj Action", - description: "Action without input, but with object output", - output: { - type: "object", - properties: { - prop1: { - type: "integer", - }, - prop2: { - type: "string", - }, - }, - required: ["prop1", "prop2"], - }, - }, - "obj-void": { - title: "obj-void Action", - description: "Action with object input, but without output", - input: { - type: "object", - properties: { - prop1: { type: "integer" }, - prop2: { type: "string" }, - }, - required: ["prop1", "prop2"], - }, - }, - }, - events: { - "on-bool": { - title: "Bool Property Change", - description: "Event with boolean data that is emitted when the bool property is written to", - data: { type: "boolean" }, - }, - "on-int": { - title: "Int Property Change", - description: "Event with integer data that is emitted when the int property is written to ", - data: { type: "integer" }, - }, - "on-num": { - title: "Num Property Change", - description: "Event with number data that is emitted when the num property is written to", - data: { type: "number" }, - }, - "on-string": { - title: "String Property Change", - description: "Event with number data that is emitted when the string property is written to", - data: { type: "number" }, - }, - "on-array": { - title: "Array Property Change", - description: "Event with number data that is emitted when the array property is written to", - data: { type: "number" }, - }, - "on-object": { - title: "Object Property Change", - description: "Event with number data that is emitted when the object property is written to", - data: { type: "number" }, - }, - }, -}) - .then((thing) => { - console.log("Produced " + thing.getThingDescription().title); - - // set property read/write handlers - thing - .setPropertyWriteHandler("bool", async (value) => { - const localBool = await value.value(); - checkPropertyWrite("boolean", typeof localBool); - bool = localBool as boolean; - thing.emitEvent("on-bool", bool); - }) - .setPropertyReadHandler("bool", async () => bool) - .setPropertyWriteHandler("int", async (value) => { - const localInt = await value.value(); - if (localInt === Math.floor(localInt as number)) { - checkPropertyWrite("integer", "integer"); - } else { - checkPropertyWrite("integer", typeof value); - } - int = localInt as number; - thing.emitEvent("on-int", int); - }) - .setPropertyReadHandler("int", async () => int) - .setPropertyWriteHandler("num", async (value) => { - const localNum = await value.value(); - checkPropertyWrite("number", typeof localNum); - num = localNum as number; - thing.emitEvent("on-num", num); - }) - .setPropertyReadHandler("num", async () => num) - .setPropertyWriteHandler("string", async (value) => { - const localString = await value.value(); - checkPropertyWrite("string", typeof localString); - string = localString as string; - thing.emitEvent("on-string", string); - }) - .setPropertyReadHandler("string", async () => string) - .setPropertyWriteHandler("array", async (value) => { - const localArray = await value.value(); - if (Array.isArray(localArray)) { - checkPropertyWrite("array", "array"); - } else { - checkPropertyWrite("array", typeof localArray); - } - array = localArray as unknown[]; - thing.emitEvent("on-array", array); - }) - .setPropertyReadHandler("array", async () => array) - .setPropertyWriteHandler("object", async (value) => { - const localObject = await value.value(); - if (Array.isArray(localObject)) { - checkPropertyWrite("object", "array"); - } else { - checkPropertyWrite("object", typeof localObject); - } - object = localObject as Record; - thing.emitEvent("on-object", object); - }) - .setPropertyReadHandler("object", async () => object); - - // set action handlers - thing - .setActionHandler("void-void", async (parameters) => { - checkActionInvocation("void-void", "undefined", typeof (await parameters.value())); - return undefined; - }) - .setActionHandler("void-int", async (parameters) => { - checkActionInvocation("void-int", "undefined", typeof (await parameters.value())); - return 0; - }) - .setActionHandler("int-void", async (parameters) => { - const localParameters = await parameters.value(); - if (localParameters === Math.floor(localParameters as number)) { - checkActionInvocation("int-void", "integer", "integer"); - } else { - checkActionInvocation("int-void", "integer", typeof parameters); - } - return undefined; - }) - .setActionHandler("int-int", async (parameters) => { - const localParameters = await parameters.value(); - if (localParameters === Math.floor(localParameters as number)) { - checkActionInvocation("int-int", "integer", "integer"); - } else { - checkActionInvocation("int-int", "integer", typeof localParameters); - } - return (localParameters as number) + 1; - }) - .setActionHandler("int-string", async (parameters) => { - const localParameters = await parameters.value(); - const inputtype = typeof localParameters; - if (localParameters === Math.floor(localParameters as number)) { - checkActionInvocation("int-string", "integer", "integer"); - } else { - checkActionInvocation("int-string", "integer", typeof localParameters); - } - - if (inputtype === "number") { - // eslint-disable-next-line no-new-wrappers - return new String(localParameters) - .replace(/0/g, "zero-") - .replace(/1/g, "one-") - .replace(/2/g, "two-") - .replace(/3/g, "three-") - .replace(/4/g, "four-") - .replace(/5/g, "five-") - .replace(/6/g, "six-") - .replace(/7/g, "seven-") - .replace(/8/g, "eight-") - .replace(/9/g, "nine-"); - } else { - throw new Error("ERROR"); - } - }) - .setActionHandler("void-obj", async (parameters) => { - checkActionInvocation("void-complex", "undefined", typeof (await parameters.value())); - return { prop1: 123, prop2: "abc" }; - }) - .setActionHandler("obj-void", async (parameters) => { - checkActionInvocation("complex-void", "object", typeof (await parameters.value())); - return undefined; - }); - - // expose the thing - thing.expose().then(() => { - console.info(thing.getThingDescription().title + " ready"); - }); - }) - .catch((e) => { - console.log(e); - });