linksmart / device-gateway

Process orchestrator and gateway between the low-level hardware access and HTTP/MQTT protocols.
Apache License 2.0
2 stars 0 forks source link

Change configuration file format to reflect the abstraction logic #44

Open farshidtz opened 5 years ago

farshidtz commented 5 years ago

Device Gateway is not directly dealing with devices and resources. It is rather dealing with a process and exposing services on its behalf.

Current main config file example:

{
  "id": "example-dgw",
  "description": "Example LinkSmart Device Gateway",
  "publicEndpoint": "http://fqdn-of-the-host:8080",
  "staticDir": "./static",
  "catalog": [],
  "http": {
    "bindAddr": "0.0.0.0",
    "bindPort": 8080
  },
  "protocols": {
    "REST": {
      "location": "/rest"
    },
    "MQTT": {
      "discover": false,
      "discoverID": "main_broker",
      "url": "tcp://localhost:1883",
      "prefix": "example-dgw",
      "offlineBuffer": 100
    }
  },
  "serviceCatalog": {
    "endpoint": "http://localhost:8082",
    "ttl": 120
  }
}

Device/resource config file (example: system):

{
  "name": "System",
  "description": "This device reports system metrics from a computer running a gateway",
  "meta": {},
  "ttl": 30,
  "resources": [
    {
      "type": "Resource",
      "name": "PS",
      "meta": {},
      "agent": {
        "type": "timer",
        "interval": 5,
        "dir": null,
        "exec": "agent-examples/system/processes.sh"
      },
      "representation": {
        "application/json": {
          "$schema": "http://json-schema.org/draft-04/schema#",
          "title": "ProcessCount",
          "description": "Total number of processes at the certain time",
          "type": "object",
          "properties": {
            "count": {
              "description": "Number of processes",
              "type": "integer"
            },
            "timestamp": {
              "description": "Linux timestamp of count measurement time",
              "type": "integer"
            }
          },
          "required": [
            "count",
            "timestamp"
          ]
        }
      },
      "protocols": [
        {
          "type": "REST",
          "methods": [
            "GET"
          ],
          "content-types": [
            "application/json"
          ]
        }
      ]
    },
    {
      "type": "Resource",
      "name": "LoadAverage",
      "meta": {},
      "agent": {
        "type": "timer",
        "interval": 30,
        "dir": null,
        "exec": "agent-examples/system/loadaverage.sh"
      },
      "representation": {
        "text/plain": {
          "type": "string"
        }
      },
      "protocols": [
        {
          "type": "REST",
          "methods": [
            "GET"
          ],
          "content-types": [
            "text/plain"
          ]
        }
      ]
    },
    {
      "type": "Resource",
      "name": "DiskUsage",
      "meta": {},
      "agent": {
        "type": "task",
        "interval": null,
        "dir": null,
        "exec": "python agent-examples/system/diskspace.py"
      },
      "representation": {
        "application/json": {
          "$schema": "http://json-schema.org/draft-04/schema#",
          "title": "DiskUsage",
          "description": "Disk usage document description",
          "type": "object",
          "properties": {
            "total": {
              "description": "Total disk usage",
              "type": "integer"
            },
            "free": {
              "description": "Free disk space",
              "type": "integer"
            },
            "used": {
              "description": "Used disk space",
              "type": "integer"
            }
          },
          "required": [
            "total",
            "free",
            "used"
          ]
        }
      },
      "protocols": [
        {
          "type": "REST",
          "methods": [
            "GET"
          ],
          "content-types": [
            "application/json"
          ]
        }
      ]
    }
  ]
}

Device/resource config file (example: mqtt-switch):

{
  "name": "MQTTSwitch",
  "description": "MQTT test switch service",
  "meta": {},
  "ttl": 120,
  "resources": [
    {
      "type": "Resource",
      "name": "Switch",
      "agent": {
        "type": "service",
        "dir": null,
        "exec": "agent-examples/mqtt-switch/switch.sh"
      },
      "representation": {},
      "protocols": [
        {
          "type": "MQTT",
          "methods": [
            "PUB",
            "SUB"
          ],
          "content-types": [
            "text/plain"
          ],
          "pub_topic": "/test/switch/pub",
          "sub_topic": "/test/switch/sub"
        },
        {
          "type": "REST",
          "methods": [
            "GET",
            "PUT"
          ],
          "content-types": [
            "text/plain"
          ]
        }
      ]
    }
  ]
}

Device/resource config file (example: speakers):

{
  "name": "AudioDevice",
  "description": "This actuator allows to generate speech from a given text and play on the speakers connected to the gateway",
  "meta": {},
  "ttl": 60,
  "resources": [
    {
      "type": "Resource",
      "name": "TTS",
      "meta": {},
      "agent": {
        "type": "task",
        "dir": null,
        "exec": "agent-examples/speakers/say.sh"
      },
      "representation": {
        "text/plain": {
          "type": "string"
        }
      },
      "protocols": [
        {
          "type": "REST",
          "methods": [
            "PUT"
          ],
          "content-types": [
            "text/plain"
          ]
        }
      ]
    }
  ]
}

Device/resource config file (example: dummy):

{
  "name": "DummyDevice",
  "description": "Dummy device producing random numbers, published to the broker",
  "meta": {"any":"key", "kind":"dummy"},
  "ttl": 30,
  "resources": [
    {
      "type": "Resource",
      "name": "RandomStream",
      "meta": {},
      "agent": {
        "type": "service",
        "dir": null,
        "exec": "while true; do echo $RANDOM; sleep 10; done"
      },
      "representation": {
        "text/plain": {
          "type": "number"
        }
      },
      "protocols": [
        {
          "type": "MQTT",
          "methods": [
            "PUB"
          ],
          "content-types": [
            "text/plain"
          ],
          "pub_retained": false
        }
      ]
    }
  ]
}

Device/resource config file (example: remote-tasks):

{
  "name": "command",
  "description": "Executes commands locally",
  "meta": {},
  "ttl": 0,
  "resources": [
    {
      "type": "Resource",
      "name": "logs",
      "agent": {
        "type": "task",
        "dir": null,
        "exec": "tail -1000 ~/logs/device-gateway.log"
      },
      "representation": {},
      "protocols": [
        {
          "type": "REST",
          "methods": [
            "GET"
          ],
          "content-types": [
            "text/plain"
          ]
        }
      ]
    },
    {
      "type": "Resource",
      "name": "reboot",
      "agent": {
        "type": "task",
        "dir": null,
        "exec": "sudo reboot"
      },
      "representation": {},
      "protocols": [
        {
          "type": "REST",
          "methods": [
            "PUT"
          ],
          "content-types": []
        }
      ]
    }
  ]
}
farshidtz commented 5 years ago

DRAFT Updated main config file:

{
    "id": "example-dgw",
    "description": "Example Device Gateway Configuration",
    "protocols": {
        "HTTP": {
            "publicEndpoint": "http://fqdn-of-the-host:8080",
            "bindAddr": "0.0.0.0",
            "bindPort": 8080,
            "basePath": "/rest"
        },
        "MQTT": {
            "discover": false, // discover from service catalog
            "discoverID": "main_broker",
            "uri": "tcp://localhost:1883",
            "offlineBuffer": 100
        }
    },
    "serviceCatalog": {
        "endpoint": "http://localhost:8082",
        "ttl": 120
    }
}

DRAFT Updated resource config:

{
    "name": "MQTTSwitch", // service id becomes example-dgw/MQTTSwitch
    "description": "MQTT test switch service",
    "meta": {},
    "agent": {
        "type": "service",
        "dir": "agent-examples/mqtt-switch",
        "exec": "switch.sh"
    },
    "contentType": "application/json",
    "protocols": [
        {
            "type": "MQTT",
            "methods": [
                "PUB",
                "SUB"
            ],
            "pubTopic": "test/switch/pub",
            "pubRetained": true, // overrides default (false)
            "pubQoS": 2, // overrides default (1)
            "subTopic": "test/switch/sub",
            "subQoS": 2, // overrides default (1)
            "broker": { // overrides default (main config file)
                "discover": false,
                "discoverID": "main_broker",
                "uri": "tcp://localhost:1883",
                "offlineBuffer": 100
            }
        },
        {
            "type": "HTTP",
            "methods": [
                "GET",
                "PUT"
            ],
           "path": "mqtt_switch"
        }
    ]
}
farshidtz commented 5 years ago

@dschowta what about this:

SUB using different topic and broker:

{
    "name": "MQTTSwitch",
    "description": "MQTT test switch service",
    "meta": {},
    "agent": {
        "type": "service",
        "dir": "agent-examples/mqtt-switch",
        "exec": "switch.sh"
    },
    "contentType": "application/json",
    "protocols": [
        {
            "type": "MQTT",
            "methods": [
                "PUB"
            ],
            "topic": "test/switch/pub",
            "retained": true,
            "qos": 2
        },
        {
            "type": "MQTT",
            "methods": [
                "SUB"
            ],
            "topic": "test/switch/sub",
            "qos": 2,
            "broker": {
                "discover": false,
                "discoverID": "main_broker",
                "uri": "tcp://localhost:1883",
                "prefix": "example-dgw",
                "offlineBuffer": 100
            }
        },
        {
            "type": "HTTP",
            "methods": [
                "GET",
                "PUT"
            ],
            "path": "mqtt_switch"
        }
    ]
}

In this example, SUB and PUB can be merged when they share the same topic and broker.

farshidtz commented 5 years ago

A protocol definition like this would lead to a device getting back its own outgoing messages and potentially cause an endless loop.

{
    "type": "MQTT",
    "methods": [
        "PUB", "SUB"
    ],
    "topic": "test/switch",
}

Could use the following and programmatically enforce different topics for PUB and SUB:

{
      "type": "MQTT",
      "pubTopic": "dummy/pub",
      "pubQoS": 1,
      "pubRetained": false,
      "subTopic": "dummy-device",
      "subQoS": 1
}

Also, in the above format, we won't be using method term in place of the MQTT Control Packet.