Hi,
I've done it for the netatmo API. It's a compacted dsm implementation (one node). Maybe you can adapt it for your use or get the idea.
Dsm-configuration:
{
"currentState": "idle",
"states": {
"idle": {
"get_data": "evaluate",
"reset": "idle"
},
"evaluate": {
"end": "idle",
"reset": "idle"
}
},
"data": {
"BASE_URL": "https://api.netatmo.net",
"client_id": "",
"client_secret": "",
"username": "",
"password": "",
"indoor_t": {
"name":"indoorTemp",
"service_name":"indoorTemp",
"characteristic":"CurrentTemperature"
},
"indoor_h": {
"name":"indoor_humidity",
"service_name":"indoor_humidity",
"characteristic":"CurrentRelativeHumidity"
},
"indoor_co2": {
"name":"indoor_co2",
"service_name":"indoor_co2",
"characteristic":"CarbonDioxideLevel"
},
"outdoor_t": {
"name":"outdoorTemp",
"service_name":"outdoorTemp",
"characteristic":"CurrentTemperature"
},
"outdoor_h": {
"name":"outdoor_humidity",
"service_name":"outdoor_humidity",
"characteristic":"CurrentRelativeHumidity"
},
"outdoor_p": {
"name":"outdoor_pressure",
"service_name":"outdoor_pressure",
"characteristic":"CurrentAirPressure"
}
},
"methods": {
"init": [
"sm.request = require('request'); /* todo: move to GOT */",
"sm.util = require('util');",
"clearTimeout(timeout.id);",
"sm.authenticate_refresh = function(refresh_token) {",
"var url = sm.util.format('%s/oauth2/token', sm.data.BASE_URL);",
"var form = {",
"client_id: sm.data.client_id,",
"client_secret: sm.data.client_secret,",
"refresh_token: refresh_token,",
"grant_type: 'refresh_token'",
"};",
"sm.request({url: url, method: 'POST', form: form,}, function(err, response, body) {",
"if (err || response.statusCode != 200) {",
"node.warn(response);",
"} else {",
"var body = JSON.parse(body);",
"sm.access_token = body.access_token;",
"if (body.expires_in) {",
"sm.expires_in = body.expires_in;",
"timeout.id = setTimeout(sm.authenticate_refresh, body.expires_in * 1000, body.refresh_token);",
"}",
"node.warn(JSON.stringify({",
"method: 'authenticate_refresh',",
"access_token: sm.access_token,",
"expires_in: sm.expires_in",
"}));",
"};",
"});",
"};"
],
"authenticate": [
"var url = sm.util.format('%s/oauth2/token', sm.data.BASE_URL);",
"var form = {",
"client_id: sm.data.client_id,",
"client_secret: sm.data.client_secret,",
"username: sm.data.username,",
"password: sm.data.password,",
"scope: 'read_station',",
"grant_type: 'password'",
"};",
"sm.request({url: url, method: 'POST', form: form,}, function(err, response, body) {",
"if (err || response.statusCode != 200) {",
"node.warn(response);",
"resume('reset', msg)",
"} else {",
"var body = JSON.parse(body);",
"sm.access_token = body.access_token;",
"if (body.expires_in) {",
"sm.expires_in = body.expires_in;",
"timeout.id = setTimeout(sm.authenticate_refresh, body.expires_in * 1000, body.refresh_token);",
"}",
"node.warn(JSON.stringify({",
"method: 'authenticate',",
"access_token: sm.access_token,",
"expires_in: sm.expires_in",
"}));",
"resume('get_data', msg);",
"};",
"});",
"sm.fill = 'yellow';",
"sm.text = 'authenticate'"
],
"get_data": [
"if (typeof sm.access_token === 'undefined') {",
"node.warn('sm.access_token undefined');",
"resume('authenticate', msg);",
"} else {",
"var url = sm.util.format('%s/api/getstationsdata', sm.data.BASE_URL);",
"var form = {",
"access_token: sm.access_token,",
"};",
"sm.request({url: url, method: 'POST', form: form,}, function(err, response, body) {",
"if (err || response.statusCode != 200) {",
"node.warn(response);",
"/* todo: if access token experired > authenticate */",
"resume('reset', msg)",
"} else {",
"var body = JSON.parse(body);",
"sm.devices = body.body.devices[0];",
"/* node.warn(sm.devices); */",
"resume('evaluate', msg);",
"};",
"});",
"sm.fill = 'yellow';",
"sm.text = 'get_data'",
"};"
],
"evaluate": [
"var msg = {};",
"msg.topic = 'netatmo';",
"var indoor_data = sm.devices.dashboard_data;",
"var outdoor_data = sm.devices.modules[0].dashboard_data;",
"if (typeof indoor_data !== 'undefined') {",
"msg.payload = sm.data.indoor_t;",
"msg.payload.value = indoor_data.Temperature;",
"node.send(RED.util.cloneMessage(msg));",
"msg.payload = sm.data.indoor_h;",
"msg.payload.value = indoor_data.Humidity;",
"node.send(RED.util.cloneMessage(msg));",
"msg.payload = sm.data.indoor_co2;",
"msg.payload.value = indoor_data.CO2;",
"node.send(RED.util.cloneMessage(msg));",
"msg.payload = sm.data.outdoor_p;",
"msg.payload.value = indoor_data.Pressure;",
"node.send(RED.util.cloneMessage(msg));",
"} else {",
"node.warn('indoor dashboard_data undefined');",
"};",
"if (typeof outdoor_data !== 'undefined') {",
"msg.payload = sm.data.outdoor_t;",
"msg.payload.value = outdoor_data.Temperature;",
"node.send(RED.util.cloneMessage(msg));",
"msg.payload = sm.data.outdoor_h;",
"msg.payload.value = outdoor_data.Humidity;",
"node.send(RED.util.cloneMessage(msg));",
"} else {",
"node.warn('outdoor dashboard_data undefined');",
"};",
"sm.fill = 'yellow';",
"sm.text = 'evaluate';",
"resume('end', msg);"
],
"end": [
"sm.fill = 'green';",
"sm.text = 'end';"
],
"reset": [
"sm.fill = 'grey';",
"sm.text = ''reset;"
],
"onAfterTransition": [
"output = false;"
],
"status": {
"fill": {
"get": "sm.fill"
},
"shape": "dot",
"text": {
"get": "sm.text"
}
}
}
}