@thingweb/node-red-node-wot
Version:
Web of Things nodes for Node-RED using node-wot
1,251 lines (1,228 loc) • 32 kB
text/typescript
const PROTOCOLS = ["http", "ws", "coap", "mqtt", "opcua", "modbus"]
const DATATYPES = {
string: {
inputMode: "text",
typeConvert: "String",
},
number: {
inputMode: "number",
typeConvert: "Number",
},
integer: {
inputMode: "number",
typeConvert: "Number",
},
boolean: {
inputMode: "text",
typeConvert: "JSON.parse",
},
object: {
inputMode: "textarea",
typeConvert: "JSON.parse",
},
array: {
inputMode: "textarea",
typeConvert: "JSON.parse",
},
propertyTypeNull: {
inputMode: "text",
typeConvert: "JSON.parse",
},
actionInputTypeNull: {
inputMode: null,
typeConvert: "",
},
}
const COMMON_ID_COUNT = 7
const PROPERTY_ID_COUNT = 19
const ACTION_ID_COUNT = 14
const EVENT_ID_COUNT = 7
/** initial y for putting node on canvas */
const INITIAL_Y = 40
/** gap of y for putting node on canvas */
const Y_GAP = 50
/** index of common-genid for ui-base node in template */
const UIBASE_ID_INDEX = 3
export const createClientFlowUsingDashboard = (tdString: string, existedNodes: any) => {
let existedUiBaseId
for (let node of existedNodes) {
if (node.type === "ui-base" && node.name === "things-dashboard") {
existedUiBaseId = node.id
}
}
const td = JSON.parse(tdString)
const commonGenIds: string[] = []
for (let i = 0; i < COMMON_ID_COUNT; i++) {
commonGenIds.push(generateId())
}
if (existedUiBaseId) {
commonGenIds[UIBASE_ID_INDEX] = existedUiBaseId
}
let flow = []
const tdTitle = td.title
const tdDescription = td.description
const availableBinding = {}
PROTOCOLS.forEach((protocol) => {
availableBinding[protocol] = checkBinding(tdString, protocol)
})
const commonParams = {
tdTitle,
tdDescription,
tdString,
td: JSON.stringify(td).replace(/\"/g, `\\"`),
...availableBinding,
}
let offsetY = INITIAL_Y
let flowAndOffsetY = makeCommonFlow(commonGenIds, commonParams, offsetY, existedUiBaseId)
flow = flow.concat(flowAndOffsetY.flow)
if (td.properties) {
for (let propertyName in td.properties) {
const propertyGenIds: string[] = []
for (let i = 0; i < PROPERTY_ID_COUNT; i++) {
propertyGenIds.push(generateId())
}
const tdProperty = td.properties[propertyName]
const propertyParams = {
...commonParams,
propertyName,
propertyDescription: tdProperty.description,
propertyObserve: tdProperty.observable || false,
inputMode: DATATYPES[tdProperty.type || "propertyTypeNull"].inputMode,
convert: DATATYPES[tdProperty.type || "propertyTypeNull"].typeConvert,
}
flowAndOffsetY = makePropertyFlow(
commonGenIds,
propertyGenIds,
propertyParams,
tdProperty,
flowAndOffsetY.offsetY
)
flow = flow.concat(flowAndOffsetY.flow)
}
}
if (td.actions) {
for (let actionName in td.actions) {
const actionGenIds: string[] = []
for (let i = 0; i < ACTION_ID_COUNT; i++) {
actionGenIds.push(generateId())
}
const tdAction = td.actions[actionName]
let actionInputType = tdAction.input?.type || "actionInputTypeNull"
const actionParams = {
...commonParams,
actionName,
actionDescription: tdAction.description,
inputMode: DATATYPES[actionInputType].inputMode,
convert: DATATYPES[actionInputType].typeConvert,
}
flowAndOffsetY = makeActionFlow(commonGenIds, actionGenIds, actionParams, tdAction, flowAndOffsetY.offsetY)
flow = flow.concat(flowAndOffsetY.flow)
}
}
if (td.events) {
for (let eventName in td.events) {
const eventGenIds: string[] = []
for (let i = 0; i < EVENT_ID_COUNT; i++) {
eventGenIds.push(generateId())
}
const tdEvent = td.events[eventName]
const eventParams = {
...commonParams,
eventName,
eventDescription: tdEvent.description,
}
flowAndOffsetY = makeEventFlow(commonGenIds, eventGenIds, eventParams, flowAndOffsetY.offsetY)
flow = flow.concat(flowAndOffsetY.flow)
}
}
const flowString = JSON.stringify(flow)
var importOptions = { generateIds: false, addFlow: true }
//@ts-ignore
RED.view.importNodes(flowString, importOptions)
}
const replaceAll = (text, pattern, replacement) => {
while (true) {
let after = text.replace(pattern, replacement)
if (text !== after) {
text = after
} else {
break
}
}
return text
}
const replaceIds = (flowStr, ids, prefix) => {
if (ids) {
for (let i = 0; i < ids.length; i++) {
flowStr = replaceAll(flowStr, `<%${prefix}-genid(${i})%>`, ids[i])
}
}
return flowStr
}
const replaceParamsAndIds = (
flowTemplate,
params,
commonGenIds,
propertyGenIds,
actionGenIds,
eventGenIds,
offsetY
) => {
let flowStr = flowTemplate
if (params) {
for (let key in params) {
flowStr = replaceAll(flowStr, `<%${key}%>`, params[key])
}
}
flowStr = replaceIds(flowStr, commonGenIds, "common")
flowStr = replaceIds(flowStr, propertyGenIds, "property")
flowStr = replaceIds(flowStr, actionGenIds, "action")
flowStr = replaceIds(flowStr, eventGenIds, "event")
for (let y = 0; true; y++) {
if (flowStr.indexOf(`<%y${y}%>`) === -1) {
break
}
flowStr = replaceAll(flowStr, `<%y${y}%>`, offsetY)
offsetY += Y_GAP
}
let flow = JSON.parse(flowStr)
return { flow, offsetY }
}
const makeCommonFlow = (commonGenIds, params, offsetY, existedUiBaseId) => {
let flowAndOffsetY = replaceParamsAndIds(THING_COMMON_TEMP, params, commonGenIds, null, null, null, offsetY)
// if ui-base node already existed on canvas, remove the node from new flow
let flow = flowAndOffsetY.flow.filter((node) => node.id !== existedUiBaseId)
flowAndOffsetY.flow = flow
return flowAndOffsetY
}
const makePropertyFlow = (commonGenIds, propertyGenIds, params, tdProperty, offsetY) => {
let flow = []
let flowAndOffsetY = replaceParamsAndIds(
PROPERTY_COMMON_TEMP,
params,
commonGenIds,
propertyGenIds,
null,
null,
offsetY
)
flow = flow.concat(flowAndOffsetY.flow)
if (!tdProperty.writeOnly) {
flowAndOffsetY = replaceParamsAndIds(
PROPERTY_READ_TEMP,
params,
commonGenIds,
propertyGenIds,
null,
null,
flowAndOffsetY.offsetY
)
flow = flow.concat(flowAndOffsetY.flow)
if (["integer", "number"].includes(tdProperty.type)) {
flowAndOffsetY = replaceParamsAndIds(
PROPERTY_READ_CHART_TEMP,
params,
commonGenIds,
propertyGenIds,
null,
null,
flowAndOffsetY.offsetY
)
flow = flow.concat(flowAndOffsetY.flow)
}
}
if (!tdProperty.readOnly) {
flowAndOffsetY = replaceParamsAndIds(
PROPERTY_WRITE_TEMP,
params,
commonGenIds,
propertyGenIds,
null,
null,
flowAndOffsetY.offsetY
)
flow = flow.concat(flowAndOffsetY.flow)
}
return { flow, offsetY: flowAndOffsetY.offsetY }
}
const makeActionFlow = (commonGenIds, actionGenIds, params, tdAction, offsetY) => {
let flow = []
let flowAndOffsetY = replaceParamsAndIds(
ACTION_COMMON_TEMP,
params,
commonGenIds,
null,
actionGenIds,
null,
offsetY
)
flow = flow.concat(flowAndOffsetY.flow)
if (params.inputMode) {
flowAndOffsetY = replaceParamsAndIds(
ACTION_ARGS_TEMP,
params,
commonGenIds,
null,
actionGenIds,
null,
flowAndOffsetY.offsetY
)
flow = flow.concat(flowAndOffsetY.flow)
}
flowAndOffsetY = replaceParamsAndIds(
ACTION_BUTTON_TEMP,
params,
commonGenIds,
null,
actionGenIds,
null,
flowAndOffsetY.offsetY
)
flow = flow.concat(flowAndOffsetY.flow)
return { flow, offsetY: flowAndOffsetY.offsetY }
}
const makeEventFlow = (commonGenIds, eventGenIds, params, offsetY) => {
let flowAndOffsetY = replaceParamsAndIds(EVENT_TEMP, params, commonGenIds, null, null, eventGenIds, offsetY)
return flowAndOffsetY
}
/**
* <copy from @node-red/util/lib/util.js>
*
* Generates a psuedo-unique-random id.
* @return {String} a random-ish id
* @memberof @node-red/util_util
*/
function generateId() {
var bytes = []
for (var i = 0; i < 8; i++) {
bytes.push(
//@ts-ignore
Math.round(0xff * Math.random())
.toString(16)
.padStart(2, "0")
)
}
return bytes.join("")
}
const detectProtocolSchemes = (window as any).tdUtils?.detectProtocolSchemes;
function checkBinding(tdStr: string, binding: string) {
// In case of OPC UA we look for opc.tcp in href not opcua
binding = binding === "opcua" ? "opc.tcp" : binding
// Also different for Modbus
binding = binding === "modbus" ? "modbus+tcp" : binding
const bindings = Object.keys(detectProtocolSchemes(tdStr))
return bindings.some(b => b === binding || b === binding + 's')
}
const THING_COMMON_TEMP = `[
{
"id": "<%common-genid(0)%>",
"type": "comment",
"z": "",
"name": "Title: <%tdTitle%>",
"info": "",
"x": 90,
"y": <%y0%>,
"wires": []
},
{
"id": "<%common-genid(1)%>",
"type": "consumed-thing",
"tdLink": "",
"td": "<%td%>",
"http": <%http%>,
"ws": <%ws%>,
"coap": <%coap%>,
"mqtt": <%mqtt%>,
"opcua": <%opcua%>,
"modbus": <%modbus%>,
"basicAuth": false,
"username": "",
"password": ""
},
{
"id": "<%common-genid(2)%>",
"type": "ui-page",
"name": "<%tdTitle%>",
"ui": "<%common-genid(3)%>",
"path": "/<%tdTitle%>",
"icon": "no-icon",
"layout": "grid",
"theme": "<%common-genid(4)%>",
"order": -1,
"className": "",
"visible": "true",
"disabled": "false"
},
{
"id": "<%common-genid(3)%>",
"type": "ui-base",
"name": "things-dashboard",
"path": "/dashboard",
"includeClientData": true,
"acceptsClientConfig": [
"ui-notification",
"ui-control"
],
"showPathInSidebar": false,
"navigationStyle": "default"
},
{
"id": "<%common-genid(4)%>",
"type": "ui-theme",
"name": "things theme",
"colors": {
"surface": "#ffffff",
"primary": "#0094ce",
"bgPage": "#eeeeee",
"groupBg": "#ffffff",
"groupOutline": "#cccccc"
},
"sizes": {
"pagePadding": "12px",
"groupGap": "12px",
"groupBorderRadius": "4px",
"widgetGap": "12px"
}
},
{
"id": "<%common-genid(5)%>",
"type": "ui-group",
"name": "header",
"page": "<%common-genid(2)%>",
"width": "12",
"height": "1",
"order": -1,
"showTitle": false,
"className": "",
"visible": "true",
"disabled": "false"
},
{
"id": "<%common-genid(6)%>",
"type": "ui-text",
"z": "",
"group": "<%common-genid(5)%>",
"order": 0,
"width": 0,
"height": 0,
"name": "",
"label": "<%tdDescription%>",
"format": "{{msg.payload}}",
"layout": "row-spread",
"style": false,
"font": "",
"fontSize": 16,
"color": "#717171",
"className": "",
"x": 140,
"y": <%y1%>,
"wires": []
}
]`
const PROPERTY_COMMON_TEMP = `[
{
"id": "<%property-genid(0)%>",
"type": "comment",
"z": "",
"name": "Property: <%propertyName%>",
"info": "",
"x": 140,
"y": <%y0%>,
"wires": []
},
{
"id": "<%property-genid(1)%>",
"type": "ui-group",
"name": "Property: <%propertyName%>",
"page": "<%common-genid(2)%>",
"width": "12",
"height": "1",
"order": 1,
"showTitle": true,
"className": "",
"visible": "true",
"disabled": "false"
},
{
"id": "<%property-genid(2)%>",
"type": "ui-text",
"z": "",
"group": "<%property-genid(1)%>",
"order": 1,
"width": 0,
"height": 0,
"name": "",
"label": "<%propertyDescription%>",
"format": "{{msg.payload}}",
"layout": "row-spread",
"style": false,
"font": "",
"fontSize": 16,
"color": "#717171",
"className": "",
"x": 180,
"y": <%y1%>,
"wires": []
}
]`
const PROPERTY_READ_TEMP = `[
{
"id": "<%property-genid(3)%>",
"type": "ui-button",
"z": "",
"group": "<%property-genid(1)%>",
"name": "",
"label": "read",
"order": 4,
"width": 0,
"height": 0,
"passthru": false,
"tooltip": "",
"color": "",
"bgcolor": "",
"className": "",
"icon": "",
"payload": "",
"payloadType": "str",
"topic": "topic",
"topicType": "msg",
"x": 180,
"y": <%y0%>,
"wires": [
[
"<%property-genid(4)%>",
"<%property-genid(6)%>"
]
]
},
{
"id": "<%property-genid(4)%>",
"type": "function",
"z": "",
"name": "invoke time",
"func": "msg.payload = \`property read invoked (\${new Date().toLocaleString()})\`\\nreturn msg",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 480,
"y": <%y0%>,
"wires": [
[
"<%property-genid(5)%>"
]
]
},
{
"id": "<%property-genid(5)%>",
"type": "ui-text",
"z": "",
"group": "<%property-genid(1)%>",
"order": 5,
"width": 0,
"height": 0,
"name": "",
"label": "",
"format": "{{msg.payload}}",
"layout": "row-spread",
"style": false,
"font": "",
"fontSize": "16",
"color": "#717171",
"className": "",
"x": 780,
"y": <%y0%>,
"wires": []
},
{
"id": "<%property-genid(6)%>",
"type": "read-property",
"z": "",
"name": "",
"topic": "",
"thing": "<%common-genid(1)%>",
"property": "<%propertyName%>",
"uriVariables": "{}",
"observe": <%propertyObserve%>,
"x": 480,
"y": <%y1%>,
"wires": [
[
"<%property-genid(7)%>",
"<%property-genid(9)%>"
]
]
},
{
"id": "<%property-genid(7)%>",
"type": "function",
"z": "",
"name": "characterization",
"func": "msg.payload = \`\${JSON.stringify(msg.payload)} (\${new Date().toLocaleString()})\`\\nreturn msg",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 780,
"y": <%y1%>,
"wires": [
[
"<%property-genid(8)%>"
]
]
},
{
"id": "<%property-genid(8)%>",
"type": "ui-text",
"z": "",
"group": "<%property-genid(1)%>",
"order": 2,
"width": 0,
"height": 0,
"name": "",
"label": "latest value",
"format": "{{msg.payload}}",
"layout": "row-spread",
"style": false,
"font": "",
"fontSize": 16,
"color": "#717171",
"className": "",
"x": 1080,
"y": <%y1%>,
"wires": []
}
]`
const PROPERTY_READ_CHART_TEMP = `[
{
"id": "<%property-genid(9)%>",
"type": "ui-chart",
"z": "",
"group": "<%property-genid(1)%>",
"name": "",
"label": "<%propertyName%> chart",
"order": 3,
"chartType": "line",
"category": "<%propertyName%>",
"categoryType": "str",
"xAxisProperty": "",
"xAxisPropertyType": "msg",
"xAxisType": "time",
"yAxisProperty": "",
"ymin": "",
"ymax": "",
"action": "append",
"pointShape": "circle",
"pointRadius": 4,
"showLegend": true,
"removeOlder": 1,
"removeOlderUnit": "3600",
"removeOlderPoints": "",
"colors": [
"#1f77b4",
"#aec7e8",
"#ff7f0e",
"#2ca02c",
"#98df8a",
"#d62728",
"#ff9896",
"#9467bd",
"#c5b0d5"
],
"width": 12,
"height": 6,
"className": "",
"x": 780,
"y": <%y0%>,
"wires": [
[]
]
}
]`
const PROPERTY_WRITE_TEMP = `[
{
"id": "<%property-genid(10)%>",
"type": "ui-text-input",
"z": "",
"group": "<%property-genid(1)%>",
"name": "write data",
"label": "write data",
"order": 6,
"width": "7",
"height": "1",
"topic": "topic",
"topicType": "msg",
"mode": "<%inputMode%>",
"delay": 300,
"passthru": true,
"sendOnDelay": false,
"sendOnBlur": true,
"sendOnEnter": false,
"className": "",
"x": 180,
"y": <%y0%>,
"wires": [
[
"<%property-genid(11)%>"
]
]
},
{
"id": "<%property-genid(11)%>",
"type": "change",
"z": "",
"name": "",
"rules": [
{
"t": "set",
"p": "propertyWriteValue_<%property-genid(12)%>",
"pt": "flow",
"to": "payload",
"tot": "msg"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 480,
"y": <%y0%>,
"wires": [
[]
]
},
{
"id": "<%property-genid(13)%>",
"type": "ui-button",
"z": "",
"group": "<%property-genid(1)%>",
"name": "",
"label": "write",
"order": 7,
"width": "5",
"height": "1",
"passthru": false,
"tooltip": "",
"color": "",
"bgcolor": "",
"className": "",
"icon": "",
"iconPosition": "left",
"payload": "",
"payloadType": "str",
"topic": "topic",
"topicType": "msg",
"x": 180,
"y": <%y1%>,
"wires": [
[
"<%property-genid(14)%>"
]
]
},
{
"id": "<%property-genid(14)%>",
"type": "change",
"z": "",
"name": "",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "propertyWriteValue_<%property-genid(12)%>",
"tot": "flow"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 480,
"y": <%y1%>,
"wires": [
[
"<%property-genid(15)%>",
"<%property-genid(17)%>"
]
]
},
{
"id": "<%property-genid(15)%>",
"type": "function",
"z": "",
"name": "invoke time",
"func": "msg.payload = \`property write invoked (\${new Date().toLocaleString()})\`\\nreturn msg",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 780,
"y": <%y1%>,
"wires": [
[
"<%property-genid(16)%>"
]
]
},
{
"id": "<%property-genid(16)%>",
"type": "ui-text",
"z": "",
"group": "<%property-genid(1)%>",
"order": 8,
"width": 0,
"height": 0,
"name": "",
"label": "",
"format": "{{msg.payload}}",
"layout": "row-spread",
"style": false,
"font": "",
"fontSize": 16,
"color": "#717171",
"className": "",
"x": 1080,
"y": <%y1%>,
"wires": []
},
{
"id": "<%property-genid(17)%>",
"type": "function",
"z": "",
"name": "change data type",
"func": "msg.payload = <%convert%>(msg.payload)\\nreturn msg",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 780,
"y": <%y2%>,
"wires": [
[
"<%property-genid(18)%>"
]
]
},
{
"id": "<%property-genid(18)%>",
"type": "write-property",
"z": "",
"name": "",
"topic": "",
"thing": "<%common-genid(1)%>",
"property": "<%propertyName%>",
"uriVariables": "{}",
"x": 1080,
"y": <%y2%>,
"wires": []
}
]`
const ACTION_COMMON_TEMP = `[
{
"id": "<%action-genid(0)%>",
"type": "comment",
"z": "",
"name": "Action: <%actionName%>",
"info": "",
"x": 140,
"y": <%y0%>,
"wires": []
},
{
"id": "<%action-genid(1)%>",
"type": "ui-group",
"name": "Action: <%actionName%>",
"page": "<%common-genid(2)%>",
"width": "12",
"height": "1",
"order": 2,
"showTitle": true,
"className": "",
"visible": "true",
"disabled": "false"
},
{
"id": "<%action-genid(13)%>",
"type": "ui-text",
"z": "",
"group": "<%action-genid(1)%>",
"order": 1,
"width": 0,
"height": 0,
"name": "",
"label": "<%actionDescription%>",
"format": "{{msg.payload}}",
"layout": "row-spread",
"style": false,
"font": "",
"fontSize": 16,
"color": "#717171",
"className": "",
"x": 180,
"y": <%y1%>,
"wires": []
}
]`
const ACTION_ARGS_TEMP = `[
{
"id": "<%action-genid(2)%>",
"type": "ui-text-input",
"z": "",
"group": "<%action-genid(1)%>",
"name": "",
"label": "argument of action",
"order": 2,
"width": "7",
"height": "1",
"topic": "topic",
"topicType": "msg",
"mode": "<%inputMode%>",
"delay": 300,
"passthru": true,
"sendOnDelay": false,
"sendOnBlur": true,
"sendOnEnter": false,
"className": "",
"x": 180,
"y": <%y0%>,
"wires": [
[
"<%action-genid(3)%>"
]
]
},
{
"id": "<%action-genid(3)%>",
"type": "change",
"z": "",
"name": "",
"rules": [
{
"t": "set",
"p": "actionArg_<%action-genid(4)%>",
"pt": "flow",
"to": "payload",
"tot": "msg"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 480,
"y": <%y0%>,
"wires": [
[]
]
}
]`
const ACTION_BUTTON_TEMP = `[
{
"id": "<%action-genid(5)%>",
"type": "ui-button",
"z": "",
"group": "<%action-genid(1)%>",
"name": "",
"label": "execute",
"order": 3,
"width": "5",
"height": "1",
"passthru": false,
"tooltip": "",
"color": "",
"bgcolor": "",
"className": "",
"icon": "",
"iconPosition": "left",
"payload": "",
"payloadType": "str",
"topic": "topic",
"topicType": "msg",
"x": 180,
"y": <%y0%>,
"wires": [
[
"<%action-genid(6)%>",
"<%action-genid(8)%>"
]
]
},
{
"id": "<%action-genid(6)%>",
"type": "function",
"z": "",
"name": "invoke time",
"func": "msg.payload = \`action invoked (\${new Date().toLocaleString()})\`\\nreturn msg",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 480,
"y": <%y0%>,
"wires": [
[
"<%action-genid(7)%>"
]
]
},
{
"id": "<%action-genid(7)%>",
"type": "ui-text",
"z": "",
"group": "<%action-genid(1)%>",
"order": 4,
"width": 0,
"height": 0,
"name": "",
"label": "",
"format": "{{msg.payload}}",
"layout": "row-spread",
"style": false,
"font": "",
"fontSize": 16,
"color": "#717171",
"className": "",
"x": 780,
"y": <%y0%>,
"wires": []
},
{
"id": "<%action-genid(8)%>",
"type": "change",
"z": "",
"name": "",
"rules": [
{
"t": "set",
"p": "payload",
"pt": "msg",
"to": "actionArg_<%action-genid(4)%>",
"tot": "flow"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 480,
"y": <%y1%>,
"wires": [
[
"<%action-genid(9)%>"
]
]
},
{
"id": "<%action-genid(9)%>",
"type": "function",
"z": "",
"name": "change data type",
"func": "msg.payload = <%convert%>(msg.payload)\\nreturn msg",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 780,
"y": <%y1%>,
"wires": [
[
"<%action-genid(10)%>"
]
]
},
{
"id": "<%action-genid(10)%>",
"type": "invoke-action",
"z": "",
"name": "",
"topic": "",
"thing": "<%common-genid(1)%>",
"action": "<%actionName%>",
"uriVariables": "{}",
"x": 1080,
"y": <%y1%>,
"wires": [
[
"<%action-genid(11)%>"
]
]
},
{
"id": "<%action-genid(11)%>",
"type": "function",
"z": "",
"name": "characterization",
"func": "msg.payload = \`\${JSON.stringify(msg.payload)} (\${new Date().toLocaleString()})\`\\nreturn msg",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 1380,
"y": <%y1%>,
"wires": [
[
"<%action-genid(12)%>"
]
]
},
{
"id": "<%action-genid(12)%>",
"type": "ui-text",
"z": "",
"group": "<%action-genid(1)%>",
"order": 5,
"width": 0,
"height": 0,
"name": "",
"label": "result of action",
"format": "{{msg.payload}}",
"layout": "row-spread",
"style": false,
"font": "",
"fontSize": 16,
"color": "#717171",
"className": "",
"x": 1680,
"y": <%y1%>,
"wires": []
}
]`
const EVENT_TEMP = `[
{
"id": "<%event-genid(0)%>",
"type": "comment",
"z": "",
"name": "Event: <%eventName%>",
"info": "",
"x": 140,
"y": <%y0%>,
"wires": []
},
{
"id": "<%event-genid(1)%>",
"type": "ui-group",
"name": "Event: <%eventName%>",
"page": "<%common-genid(2)%>",
"width": "12",
"height": "1",
"order": 3,
"showTitle": true,
"className": "",
"visible": "true",
"disabled": "false"
},
{
"id": "<%event-genid(6)%>",
"type": "ui-text",
"z": "",
"group": "<%event-genid(1)%>",
"order": 1,
"width": 0,
"height": 0,
"name": "",
"label": "<%eventDescription%>",
"format": "{{msg.payload}}",
"layout": "row-spread",
"style": false,
"font": "",
"fontSize": 16,
"color": "#717171",
"className": "",
"x": 180,
"y": <%y1%>,
"wires": []
},
{
"id": "<%event-genid(2)%>",
"type": "subscribe-event",
"z": "",
"name": "",
"topic": "<%tdTitle%>:<%eventName%>",
"thing": "<%common-genid(1)%>",
"event": "<%eventName%>",
"x": 180,
"y": <%y2%>,
"wires": [
[
"<%event-genid(5)%>",
"<%event-genid(3)%>"
]
]
},
{
"id": "<%event-genid(3)%>",
"type": "function",
"z": "",
"name": "make event data for display",
"func": "let events = flow.get(\\"<%tdTitle%>:<%eventName%>\\")\\nif(!events) events = []\\nevents.unshift({\\n time: new Date().toLocaleString(),\\n source: msg.topic,\\n event: JSON.stringify(msg.payload)\\n})\\nflow.set(\\"<%tdTitle%>:<%eventName%>\\", events)\\nmsg.payload = events\\nreturn msg",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 480,
"y": <%y2%>,
"wires": [
[
"<%event-genid(4)%>"
]
]
},
{
"id": "<%event-genid(4)%>",
"type": "ui-table",
"z": "",
"group": "<%event-genid(1)%>",
"name": "",
"label": "text",
"order": 2,
"width": 0,
"height": 0,
"maxrows": "10",
"autocols": true,
"columns": [],
"x": 780,
"y": <%y2%>,
"wires": []
},
{
"id": "<%event-genid(5)%>",
"type": "ui-notification",
"z": "",
"ui": "<%common-genid(3)%>",
"position": "top center",
"colorDefault": true,
"color": "#000000",
"displayTime": "3",
"showCountdown": true,
"outputs": 0,
"allowDismiss": true,
"dismissText": "Close",
"raw": false,
"className": "",
"name": "",
"x": 480,
"y": <%y3%>,
"wires": []
}
]`