From 35305fc0d250e49d01217d1fbd0fb255cb021e01 Mon Sep 17 00:00:00 2001 From: Julius Jann <23746861+wandertaker@users.noreply.github.com> Date: Tue, 8 Nov 2022 18:31:35 +0100 Subject: [PATCH] feat: support mqtts protocol (#174) Co-authored-by: Lukasz Gornicki --- README.md | 2 +- package.json | 1 + template/config/common.yml | 4 +- template/package.json | 2 +- template/src/api/index.js | 3 + test/__snapshots__/integration.test.js.snap | 363 ++++++++++++++++++++ test/integration.test.js | 56 +-- test/mocks/mqtt/asyncapi.yml | 226 ++++++++++++ 8 files changed, 629 insertions(+), 28 deletions(-) create mode 100644 test/mocks/mqtt/asyncapi.yml diff --git a/README.md b/README.md index 577b99ee..fd747c13 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ Property name | Reason | Fallback | Default ## Supported protocols * [AMQP](https://en.wikipedia.org/wiki/Advanced_Message_Queuing_Protocol) -* [MQTT](https://en.wikipedia.org/wiki/MQTT) +* [MQTT and MQTTS](https://en.wikipedia.org/wiki/MQTT) * [Kafka](https://en.wikipedia.org/wiki/Apache_Kafka) * [WebSocket](https://en.wikipedia.org/wiki/WebSocket) diff --git a/package.json b/package.json index af80110e..16f9412e 100644 --- a/package.json +++ b/package.json @@ -78,6 +78,7 @@ "supportedProtocols": [ "amqp", "mqtt", + "mqtts", "kafka", "kafka-secure", "ws" diff --git a/template/config/common.yml b/template/config/common.yml index ccdf94e3..d29d8ba8 100644 --- a/template/config/common.yml +++ b/template/config/common.yml @@ -25,9 +25,9 @@ default: durable: true autoDelete: true {%- endif %} -{%- if asyncapi.server(params.server).protocol() === "mqtt" %} +{%- if asyncapi.server(params.server).protocol() === "mqtt" or asyncapi.server(params.server).protocol() === "mqtts"%} mqtt: - url: mqtt://{{ asyncapi.server(params.server).url() | replaceServerVariablesWithValues(asyncapi.server(params.server).variables()) | stripProtocol }} + url: {{ asyncapi.server(params.server).protocol() }}://{{ asyncapi.server(params.server).url() | replaceServerVariablesWithValues(asyncapi.server(params.server).variables()) | stripProtocol }} topics: {{ asyncapi | channelNamesWithPublish | toMqttTopic | dump | safe }} qos: protocol: mqtt diff --git a/template/package.json b/template/package.json index 99f96ab8..9657a9e9 100644 --- a/template/package.json +++ b/template/package.json @@ -11,7 +11,7 @@ "hermesjs": "2.x", "hermesjs-router": "1.x", "asyncapi-validator": "3.0.0", - {% if asyncapi.server(params.server).protocol() === 'mqtt' -%} + {% if asyncapi.server(params.server).protocol() === 'mqtt' or asyncapi.server(params.server).protocol() === 'mqtts' -%} "hermesjs-mqtt": "2.x", {%- endif -%} {% if asyncapi.server(params.server).protocol() === 'kafka' or asyncapi.server(params.server).protocol() === 'kafka-secure' -%} diff --git a/template/src/api/index.js b/template/src/api/index.js index b3e5c985..d10df066 100644 --- a/template/src/api/index.js +++ b/template/src/api/index.js @@ -9,6 +9,9 @@ const logger = require('./middlewares/logger'); const errorLogger = require('./middlewares/error-logger'); const config = require('../lib/config'); {%- set protocol = asyncapi.server(params.server).protocol() %} +{%- if protocol === 'mqtts' %} + {%- set protocol = 'mqtt' %} +{%- endif %} const serverConfig = {{ protocol | getConfig }}; const {{ protocol | getProtocol | capitalize }}Adapter = require('hermesjs-{{ protocol | getProtocol }}'); {%- for channelName, channel in asyncapi.channels() %} diff --git a/test/__snapshots__/integration.test.js.snap b/test/__snapshots__/integration.test.js.snap index 82a7572d..7612bf29 100644 --- a/test/__snapshots__/integration.test.js.snap +++ b/test/__snapshots__/integration.test.js.snap @@ -166,3 +166,366 @@ router.use('smartylighting/streetlights/1/0/event/:streetlightId/lighting/measur }); " `; + +exports[`template integration tests for generated files using the generator and mqtt example should generate proper handlers and routes files 9`] = ` +"const Hermes = require('hermesjs'); +const app = new Hermes(); +const path = require('path'); +const { yellow, gray, cyan } = require('chalk'); +const buffer2string = require('./middlewares/buffer2string'); +const string2json = require('./middlewares/string2json'); +const json2string = require('./middlewares/json2string'); +const logger = require('./middlewares/logger'); +const errorLogger = require('./middlewares/error-logger'); +const config = require('../lib/config'); +const serverConfig = config.broker.mqtt; +const MqttAdapter = require('hermesjs-mqtt'); +const smartylightingStreetlights10EventStreetlightIdLightingMeasured = require('./routes/smartylighting-streetlights-1-0-event-{streetlightId}-lighting-measured.js'); +const smartylightingStreetlights10ActionStreetlightIdTurnOn = require('./routes/smartylighting-streetlights-1-0-action-{streetlightId}-turn-on.js'); +const smartylightingStreetlights10ActionStreetlightIdTurnOff = require('./routes/smartylighting-streetlights-1-0-action-{streetlightId}-turn-off.js'); +const smartylightingStreetlights10ActionStreetlightIdDim = require('./routes/smartylighting-streetlights-1-0-action-{streetlightId}-dim.js'); + +app.addAdapter(MqttAdapter, serverConfig); + +app.use(buffer2string); +app.use(string2json); +app.use(logger); + +// Channels +console.log(cyan.bold.inverse(' SUB '), gray('Subscribed to'), yellow('smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured')); +app.use(smartylightingStreetlights10EventStreetlightIdLightingMeasured); +console.log(yellow.bold.inverse(' PUB '), gray('Will eventually publish to'), yellow('smartylighting/streetlights/1/0/action/{streetlightId}/turn/on')); +app.useOutbound(smartylightingStreetlights10ActionStreetlightIdTurnOn); +console.log(yellow.bold.inverse(' PUB '), gray('Will eventually publish to'), yellow('smartylighting/streetlights/1/0/action/{streetlightId}/turn/off')); +app.useOutbound(smartylightingStreetlights10ActionStreetlightIdTurnOff); +console.log(yellow.bold.inverse(' PUB '), gray('Will eventually publish to'), yellow('smartylighting/streetlights/1/0/action/{streetlightId}/dim')); +app.useOutbound(smartylightingStreetlights10ActionStreetlightIdDim); + +app.use(errorLogger); +app.useOutbound(errorLogger); +app.useOutbound(logger); +app.useOutbound(json2string); + +app + .listen() + .then((adapters) => { + console.log(cyan.underline(\`\${config.app.name} \${config.app.version}\`), gray('is ready!'), '\\\\n'); + adapters.forEach(adapter => { + console.log('🔗 ', adapter.name(), gray('is connected!')); + }); + }) + .catch(console.error); +" +`; + +exports[`template integration tests for generated files using the generator and mqtt example should generate proper handlers and routes files 10`] = ` +"default: + app: + name: Streetlights MQTT API + version: 1.0.0 + + broker: + mqtt: + url: mqtt://test.mosquitto.org:1883 + topics: [\\"smartylighting/streetlights/1/0/event/+/lighting/measured\\"] + qos: + protocol: mqtt + retain: + subscribe: true + +development: + +test: + +staging: + +production: +" +`; + +exports[`template integration tests for generated files using the generator and mqtt example should generate proper handlers and routes files 11`] = ` +"{ + \\"name\\": \\"streetlights-mqtt-api\\", + \\"description\\": \\"The Smartylighting Streetlights API allows you to remotely manage the city lights. ### Check out its awesome features: * Turn a specific streetlight on/off 🌃 * Dim a specific streetlight 😎 * Receive real-time information about environmental lighting conditions 📈 \\", + \\"version\\": \\"1.0.0\\", + \\"scripts\\": { + \\"start\\": \\"node src/api/index.js\\" + }, + \\"dependencies\\": { + \\"chalk\\": \\"4.1.2\\", + \\"dotenv\\": \\"8.1.0\\", + \\"hermesjs\\": \\"2.x\\", + \\"hermesjs-router\\": \\"1.x\\", + \\"asyncapi-validator\\": \\"3.0.0\\", + \\"hermesjs-mqtt\\": \\"2.x\\", + + \\"node-fetch\\": \\"2.6.0\\", + \\"node-yaml-config\\": \\"0.0.4\\" + } +}" +`; + +exports[`template integration tests for generated files using the generator and mqtt example should use mqtt logic for mqtts protocol 1`] = ` +" +const handler = module.exports = {}; + +/** + * + * @param {object} options + * @param {object} options.message + * @param {integer} options.message.headers.my-app-header + * @param {integer} options.message.payload.percentage - Percentage to which the light should be dimmed to. + * @param {string} options.message.payload.sentAt - Date and time when the message was sent. + */ +handler.dimLight = async ({message}) => { + // Implement your business logic here... +}; +" +`; + +exports[`template integration tests for generated files using the generator and mqtt example should use mqtt logic for mqtts protocol 2`] = ` +" +const handler = module.exports = {}; + +/** + * + * @param {object} options + * @param {object} options.message + * @param {integer} options.message.headers.my-app-header + * @param {string} options.message.payload.command - Whether to turn on or off the light. + * @param {string} options.message.payload.sentAt - Date and time when the message was sent. + */ +handler.turnOff = async ({message}) => { + // Implement your business logic here... +}; +" +`; + +exports[`template integration tests for generated files using the generator and mqtt example should use mqtt logic for mqtts protocol 3`] = ` +" +const handler = module.exports = {}; + +/** + * + * @param {object} options + * @param {object} options.message + * @param {integer} options.message.headers.my-app-header + * @param {string} options.message.payload.command - Whether to turn on or off the light. + * @param {string} options.message.payload.sentAt - Date and time when the message was sent. + */ +handler.turnOn = async ({message}) => { + // Implement your business logic here... +}; +" +`; + +exports[`template integration tests for generated files using the generator and mqtt example should use mqtt logic for mqtts protocol 4`] = ` +" +const handler = module.exports = {}; + +/** + * Inform about environmental lighting conditions of a particular streetlight. + * @param {object} options + * @param {object} options.message + * @param {integer} options.message.headers.my-app-header + * @param {integer} options.message.payload.lumens - Light intensity measured in lumens. + * @param {string} options.message.payload.sentAt - Date and time when the message was sent. + */ +handler.receiveLightMeasurement = async ({message}) => { + // Implement your business logic here... +}; +" +`; + +exports[`template integration tests for generated files using the generator and mqtt example should use mqtt logic for mqtts protocol 5`] = ` +"const Router = require('hermesjs/lib/router'); +const {validateMessage} = require('../../lib/message-validator'); +const router = new Router(); +const smartylightingStreetlights10ActionStreetlightIdDimHandler = require('../handlers/smartylighting-streetlights-1-0-action-{streetlightId}-dim'); +module.exports = router; + + + +router.useOutbound('smartylighting/streetlights/1/0/action/:streetlightId/dim', async (message, next) => { + try { + + await validateMessage(message.payload,'smartylighting/streetlights/1/0/action/{streetlightId}/dim','dimLight','subscribe'); + await smartylightingStreetlights10ActionStreetlightIdDimHandler.dimLight({message}); + next(); + + } catch (e) { + next(e); + } +}); +" +`; + +exports[`template integration tests for generated files using the generator and mqtt example should use mqtt logic for mqtts protocol 6`] = ` +"const Router = require('hermesjs/lib/router'); +const {validateMessage} = require('../../lib/message-validator'); +const router = new Router(); +const smartylightingStreetlights10ActionStreetlightIdTurnOffHandler = require('../handlers/smartylighting-streetlights-1-0-action-{streetlightId}-turn-off'); +module.exports = router; + + + +router.useOutbound('smartylighting/streetlights/1/0/action/:streetlightId/turn/off', async (message, next) => { + try { + + await validateMessage(message.payload,'smartylighting/streetlights/1/0/action/{streetlightId}/turn/off','turnOnOff','subscribe'); + await smartylightingStreetlights10ActionStreetlightIdTurnOffHandler.turnOff({message}); + next(); + + } catch (e) { + next(e); + } +}); +" +`; + +exports[`template integration tests for generated files using the generator and mqtt example should use mqtt logic for mqtts protocol 7`] = ` +"const Router = require('hermesjs/lib/router'); +const {validateMessage} = require('../../lib/message-validator'); +const router = new Router(); +const smartylightingStreetlights10ActionStreetlightIdTurnOnHandler = require('../handlers/smartylighting-streetlights-1-0-action-{streetlightId}-turn-on'); +module.exports = router; + + + +router.useOutbound('smartylighting/streetlights/1/0/action/:streetlightId/turn/on', async (message, next) => { + try { + + await validateMessage(message.payload,'smartylighting/streetlights/1/0/action/{streetlightId}/turn/on','turnOnOff','subscribe'); + await smartylightingStreetlights10ActionStreetlightIdTurnOnHandler.turnOn({message}); + next(); + + } catch (e) { + next(e); + } +}); +" +`; + +exports[`template integration tests for generated files using the generator and mqtt example should use mqtt logic for mqtts protocol 8`] = ` +"const Router = require('hermesjs/lib/router'); +const {validateMessage} = require('../../lib/message-validator'); +const router = new Router(); +const smartylightingStreetlights10EventStreetlightIdLightingMeasuredHandler = require('../handlers/smartylighting-streetlights-1-0-event-{streetlightId}-lighting-measured'); +module.exports = router; + + + +/** + * Inform about environmental lighting conditions of a particular streetlight. + */ +router.use('smartylighting/streetlights/1/0/event/:streetlightId/lighting/measured', async (message, next) => { + try { + + await validateMessage(message.payload,'smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured','lightMeasured','publish'); + await smartylightingStreetlights10EventStreetlightIdLightingMeasuredHandler.receiveLightMeasurement({message}); + next(); + + } catch (e) { + next(e); + } +}); +" +`; + +exports[`template integration tests for generated files using the generator and mqtt example should use mqtt logic for mqtts protocol 9`] = ` +"const Hermes = require('hermesjs'); +const app = new Hermes(); +const path = require('path'); +const { yellow, gray, cyan } = require('chalk'); +const buffer2string = require('./middlewares/buffer2string'); +const string2json = require('./middlewares/string2json'); +const json2string = require('./middlewares/json2string'); +const logger = require('./middlewares/logger'); +const errorLogger = require('./middlewares/error-logger'); +const config = require('../lib/config'); +const serverConfig = config.broker.mqtt; +const MqttAdapter = require('hermesjs-mqtt'); +const smartylightingStreetlights10EventStreetlightIdLightingMeasured = require('./routes/smartylighting-streetlights-1-0-event-{streetlightId}-lighting-measured.js'); +const smartylightingStreetlights10ActionStreetlightIdTurnOn = require('./routes/smartylighting-streetlights-1-0-action-{streetlightId}-turn-on.js'); +const smartylightingStreetlights10ActionStreetlightIdTurnOff = require('./routes/smartylighting-streetlights-1-0-action-{streetlightId}-turn-off.js'); +const smartylightingStreetlights10ActionStreetlightIdDim = require('./routes/smartylighting-streetlights-1-0-action-{streetlightId}-dim.js'); + +app.addAdapter(MqttAdapter, serverConfig); + +app.use(buffer2string); +app.use(string2json); +app.use(logger); + +// Channels +console.log(cyan.bold.inverse(' SUB '), gray('Subscribed to'), yellow('smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured')); +app.use(smartylightingStreetlights10EventStreetlightIdLightingMeasured); +console.log(yellow.bold.inverse(' PUB '), gray('Will eventually publish to'), yellow('smartylighting/streetlights/1/0/action/{streetlightId}/turn/on')); +app.useOutbound(smartylightingStreetlights10ActionStreetlightIdTurnOn); +console.log(yellow.bold.inverse(' PUB '), gray('Will eventually publish to'), yellow('smartylighting/streetlights/1/0/action/{streetlightId}/turn/off')); +app.useOutbound(smartylightingStreetlights10ActionStreetlightIdTurnOff); +console.log(yellow.bold.inverse(' PUB '), gray('Will eventually publish to'), yellow('smartylighting/streetlights/1/0/action/{streetlightId}/dim')); +app.useOutbound(smartylightingStreetlights10ActionStreetlightIdDim); + +app.use(errorLogger); +app.useOutbound(errorLogger); +app.useOutbound(logger); +app.useOutbound(json2string); + +app + .listen() + .then((adapters) => { + console.log(cyan.underline(\`\${config.app.name} \${config.app.version}\`), gray('is ready!'), '\\\\n'); + adapters.forEach(adapter => { + console.log('🔗 ', adapter.name(), gray('is connected!')); + }); + }) + .catch(console.error); +" +`; + +exports[`template integration tests for generated files using the generator and mqtt example should use mqtt logic for mqtts protocol 10`] = ` +"default: + app: + name: Streetlights MQTT API + version: 1.0.0 + + broker: + mqtt: + url: mqtts://test.mosquitto.org:8886 + topics: [\\"smartylighting/streetlights/1/0/event/+/lighting/measured\\"] + qos: + protocol: mqtt + retain: + subscribe: true + +development: + +test: + +staging: + +production: +" +`; + +exports[`template integration tests for generated files using the generator and mqtt example should use mqtt logic for mqtts protocol 11`] = ` +"{ + \\"name\\": \\"streetlights-mqtt-api\\", + \\"description\\": \\"The Smartylighting Streetlights API allows you to remotely manage the city lights. ### Check out its awesome features: * Turn a specific streetlight on/off 🌃 * Dim a specific streetlight 😎 * Receive real-time information about environmental lighting conditions 📈 \\", + \\"version\\": \\"1.0.0\\", + \\"scripts\\": { + \\"start\\": \\"node src/api/index.js\\" + }, + \\"dependencies\\": { + \\"chalk\\": \\"4.1.2\\", + \\"dotenv\\": \\"8.1.0\\", + \\"hermesjs\\": \\"2.x\\", + \\"hermesjs-router\\": \\"1.x\\", + \\"asyncapi-validator\\": \\"3.0.0\\", + \\"hermesjs-mqtt\\": \\"2.x\\", + + \\"node-fetch\\": \\"2.6.0\\", + \\"node-yaml-config\\": \\"0.0.4\\" + } +}" +`; diff --git a/test/integration.test.js b/test/integration.test.js index 22c837c9..d164e89c 100644 --- a/test/integration.test.js +++ b/test/integration.test.js @@ -1,7 +1,6 @@ const path = require('path'); const Generator = require('@asyncapi/generator'); const { readFile } = require('fs').promises; -const fetch = require('node-fetch'); const MAIN_TEST_RESULT_PATH = path.join('test', 'temp', 'integrationTestResult'); @@ -13,32 +12,41 @@ const generateFolderName = () => { describe('template integration tests for generated files using the generator and mqtt example', () => { jest.setTimeout(30000); - it('should generate proper handlers and routes files', async() => { - const outputDir = generateFolderName(); - const params = { - server: 'production' - }; - const basicExampleUrl = 'https://raw.githubusercontent.com/asyncapi/spec/v2.2.0/examples/streetlights-mqtt.yml'; - const asyncapiFile = await fetch(basicExampleUrl); + it.each` + server | description + ${'production'} | ${'should generate proper handlers and routes files'} + ${'production-mqtts'} | ${'should use mqtt logic for mqtts protocol'} + `( + '$description', + async ({ server}) => { + const outputDir = generateFolderName(); + const params = { + server + }; + const mqttExamplePath = './mocks/mqtt/asyncapi.yml'; - const generator = new Generator(path.normalize('./'), outputDir, { forceWrite: true, templateParams: params }); - await generator.generateFromString(await asyncapiFile.text()); + const generator = new Generator(path.normalize('./'), outputDir, { forceWrite: true, templateParams: params }); + await generator.generateFromFile(path.resolve('test', mqttExamplePath)); - const expectedFiles = [ - '/src/api/handlers/smartylighting-streetlights-1-0-action-{streetlightId}-dim.js', - '/src/api/handlers/smartylighting-streetlights-1-0-action-{streetlightId}-turn-off.js', - '/src/api/handlers/smartylighting-streetlights-1-0-action-{streetlightId}-turn-on.js', - '/src/api/handlers/smartylighting-streetlights-1-0-event-{streetlightId}-lighting-measured.js', - '/src/api/routes/smartylighting-streetlights-1-0-action-{streetlightId}-dim.js', - '/src/api/routes/smartylighting-streetlights-1-0-action-{streetlightId}-turn-off.js', - '/src/api/routes/smartylighting-streetlights-1-0-action-{streetlightId}-turn-on.js', - '/src/api/routes/smartylighting-streetlights-1-0-event-{streetlightId}-lighting-measured.js' - ]; - for (const index in expectedFiles) { - const file = await readFile(path.join(outputDir, expectedFiles[index]), 'utf8'); - expect(file).toMatchSnapshot(); + const expectedFiles = [ + '/src/api/handlers/smartylighting-streetlights-1-0-action-{streetlightId}-dim.js', + '/src/api/handlers/smartylighting-streetlights-1-0-action-{streetlightId}-turn-off.js', + '/src/api/handlers/smartylighting-streetlights-1-0-action-{streetlightId}-turn-on.js', + '/src/api/handlers/smartylighting-streetlights-1-0-event-{streetlightId}-lighting-measured.js', + '/src/api/routes/smartylighting-streetlights-1-0-action-{streetlightId}-dim.js', + '/src/api/routes/smartylighting-streetlights-1-0-action-{streetlightId}-turn-off.js', + '/src/api/routes/smartylighting-streetlights-1-0-action-{streetlightId}-turn-on.js', + '/src/api/routes/smartylighting-streetlights-1-0-event-{streetlightId}-lighting-measured.js', + '/src/api/index.js', + '/config/common.yml', + '/package.json' + ]; + for (const index in expectedFiles) { + const file = await readFile(path.join(outputDir, expectedFiles[index]), 'utf8'); + expect(file).toMatchSnapshot(); + } } - }); + ); }); describe('template integration tests for generated files using the generator and kafka example', () => { diff --git a/test/mocks/mqtt/asyncapi.yml b/test/mocks/mqtt/asyncapi.yml new file mode 100644 index 00000000..9e400404 --- /dev/null +++ b/test/mocks/mqtt/asyncapi.yml @@ -0,0 +1,226 @@ +asyncapi: '2.2.0' +info: + title: Streetlights MQTT API + version: '1.0.0' + description: | + The Smartylighting Streetlights API allows you to remotely manage the city lights. + + ### Check out its awesome features: + + * Turn a specific streetlight on/off 🌃 + * Dim a specific streetlight 😎 + * Receive real-time information about environmental lighting conditions 📈 + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0 + +servers: + production: + url: test.mosquitto.org:{port} + protocol: mqtt + description: Test broker + variables: + port: + description: Secure connection (TLS) is available through port 8883. + default: '1883' + enum: + - '1883' + - '8883' + security: + - apiKey: [] + - supportedOauthFlows: + - streetlights:on + - streetlights:off + - streetlights:dim + - openIdConnectWellKnown: [] + production-mqtts: + url: test.mosquitto.org:{port} + protocol: mqtts + description: Test broker + variables: + port: + description: Secure connection (TLS) is available through port 8886. + default: '8886' + enum: + - '8886' + security: + - apiKey: [] + - supportedOauthFlows: + - streetlights:on + - streetlights:off + - streetlights:dim + - openIdConnectWellKnown: [] + +defaultContentType: application/json + +channels: + smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured: + description: The topic on which measured values may be produced and consumed. + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + publish: + summary: Inform about environmental lighting conditions of a particular streetlight. + operationId: receiveLightMeasurement + traits: + - $ref: '#/components/operationTraits/mqtt' + message: + $ref: '#/components/messages/lightMeasured' + + smartylighting/streetlights/1/0/action/{streetlightId}/turn/on: + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + subscribe: + operationId: turnOn + traits: + - $ref: '#/components/operationTraits/mqtt' + message: + $ref: '#/components/messages/turnOnOff' + + smartylighting/streetlights/1/0/action/{streetlightId}/turn/off: + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + subscribe: + operationId: turnOff + traits: + - $ref: '#/components/operationTraits/mqtt' + message: + $ref: '#/components/messages/turnOnOff' + + smartylighting/streetlights/1/0/action/{streetlightId}/dim: + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + subscribe: + operationId: dimLight + traits: + - $ref: '#/components/operationTraits/mqtt' + message: + $ref: '#/components/messages/dimLight' + +components: + messages: + lightMeasured: + name: lightMeasured + title: Light measured + summary: Inform about environmental lighting conditions of a particular streetlight. + contentType: application/json + traits: + - $ref: '#/components/messageTraits/commonHeaders' + payload: + $ref: "#/components/schemas/lightMeasuredPayload" + turnOnOff: + name: turnOnOff + title: Turn on/off + summary: Command a particular streetlight to turn the lights on or off. + traits: + - $ref: '#/components/messageTraits/commonHeaders' + payload: + $ref: "#/components/schemas/turnOnOffPayload" + dimLight: + name: dimLight + title: Dim light + summary: Command a particular streetlight to dim the lights. + traits: + - $ref: '#/components/messageTraits/commonHeaders' + payload: + $ref: "#/components/schemas/dimLightPayload" + + schemas: + lightMeasuredPayload: + type: object + properties: + lumens: + type: integer + minimum: 0 + description: Light intensity measured in lumens. + sentAt: + $ref: "#/components/schemas/sentAt" + turnOnOffPayload: + type: object + properties: + command: + type: string + enum: + - on + - off + description: Whether to turn on or off the light. + sentAt: + $ref: "#/components/schemas/sentAt" + dimLightPayload: + type: object + properties: + percentage: + type: integer + description: Percentage to which the light should be dimmed to. + minimum: 0 + maximum: 100 + sentAt: + $ref: "#/components/schemas/sentAt" + sentAt: + type: string + format: date-time + description: Date and time when the message was sent. + + securitySchemes: + apiKey: + type: apiKey + in: user + description: Provide your API key as the user and leave the password empty. + supportedOauthFlows: + type: oauth2 + description: Flows to support OAuth 2.0 + flows: + implicit: + authorizationUrl: 'https://authserver.example/auth' + scopes: + 'streetlights:on': Ability to switch lights on + 'streetlights:off': Ability to switch lights off + 'streetlights:dim': Ability to dim the lights + password: + tokenUrl: 'https://authserver.example/token' + scopes: + 'streetlights:on': Ability to switch lights on + 'streetlights:off': Ability to switch lights off + 'streetlights:dim': Ability to dim the lights + clientCredentials: + tokenUrl: 'https://authserver.example/token' + scopes: + 'streetlights:on': Ability to switch lights on + 'streetlights:off': Ability to switch lights off + 'streetlights:dim': Ability to dim the lights + authorizationCode: + authorizationUrl: 'https://authserver.example/auth' + tokenUrl: 'https://authserver.example/token' + refreshUrl: 'https://authserver.example/refresh' + scopes: + 'streetlights:on': Ability to switch lights on + 'streetlights:off': Ability to switch lights off + 'streetlights:dim': Ability to dim the lights + openIdConnectWellKnown: + type: openIdConnect + openIdConnectUrl: 'https://authserver.example/.well-known' + + parameters: + streetlightId: + description: The ID of the streetlight. + schema: + type: string + + messageTraits: + commonHeaders: + headers: + type: object + properties: + my-app-header: + type: integer + minimum: 0 + maximum: 100 + + operationTraits: + mqtt: + bindings: + mqtt: + qos: 1 \ No newline at end of file