Metadata-Version: 2.1
Name: enos-mqtt-sdk-python
Version: 0.0.3
Summary: EnOS MQTT SDK for Python
Home-page: https://github.com/EnvisionIot/enos-mqtt-sdk-python.git
Author: lihu.yang
Author-email: lihu.yang@envision-digital.com
License: UNKNOWN
Platform: UNKNOWN
Classifier: Programming Language :: Python :: 2.7
Description-Content-Type: text/markdown
Requires-Dist: atomic (>=0.7.3)
Requires-Dist: futures (>=3.2.0)
Requires-Dist: paho-mqtt (>=1.4.0)

# Using EnOS Device SDK for MQTT for Python (Preview Edition)

This repo contains the preview edition of EnOS Device SDK for MQTT for Python. This article instructs how to prepare your development environment to use the EnOS Device SDK for MQTT for Python.

* [Installing Python](#python)
* [Obtaining EnOS Device SDK for MQTT for Python](#obtaining)
* [Key Features](#keyfeatures)
* [Sample Code](#samplecode)

<a name="python"></a>
## Installing Python
To use the EnOS Device SDK for MQTT for Python, you will need Python 2.7.10+, and `pip` is required.

<a name="obtaining"></a>
## Obtaining EnOS Device SDK for MQTT for Python
You can obtain the SDK through the following methods:

- Install from pip
- Download the source code by cloning this repo and build on your machine

### Installing from PIP

Use the following command to install EnOS Device SDK for MQTT for Python from PIP.

```bash 
pip install enos-mqtt-sdk-python
```

### Building from Source Code
1. Obtain the EnOS Device SDK for MQTT for Python source code.
   - From GitHub:
    ```
    git clone https://github.com/EnvisionIot/enos-mqtt-sdk-python.git
    ```
   - From EnOS SDK Center. Click **SDK Center** from the left navigation of EnOS Console, and obtain the SDK source code.

2. From the directory where the source code is stored, run the following command:

   ```
   python setup.py install
   ```
<a name="keyfeatures"></a>
## Key Features

As the preview edition, the EnOS Device SDK for MQTT for Python currently contains only partial of the EnOS connection features as listed below:

- MQTT over TCP based on username and password and MQTT over TLS 1.2 with X.509 certificate-based mutual authentication supported
- Create, read, update and delete (CRUD) gateway device topology
- Publish measure point data

<a name="samplecode"></a>
## Sample Code

### Preparation (Cloud Configuration and Certificate Generation)
1. Create device models (including gateway and sub-device), products, devices, and applications in the EnOS Console, and get the corresponding product key-secret and device key-secret pair. For more information, see [Cloud Configuration](https://docs.envisioniot.com/docs/device-connection/en/latest/cloud/index.html) in EnOS Documentation Center.

2. Get the CA root certificate, and generate the local RSA private key and csr file, and apply a certificate from EnOS via the EnOS cert tool (available in EnOS SDK Center).

### Establishing Connection

1. Initialize the MQTT client and load the certificate files.
  ```python
  client = MqttClient(enos_mqtt_url, gateway_product_key, gateway_device_key, gateway_device_secret)
  client.getProfile().setSSLContext(ca_file, cer_file, key_file, key_file_password)
  ```

2. Set the online and offline callback method.
  ```python
  client.onOnline = onOnline
  client.onOffline = onOffine
  ```

3. Connect in synchronous mode.
  ```python
  client.connect()
  ```

### Sending Telemetries
1. Add topology for the sub-devices
  ```python
  topo_req = TopoAddRequest.builder().addSubDevice(SubDeviceInfo(sub_product_key, sub_device_key, sub_device_secret)).build()
  topo_res = client.publish(topo_req)
  ```

2. Login the sub-devices
  ```python
  login_req = SubDeviceLoginRequest.builder().setSubDeviceInfo(sub_product_key, sub_device_key, sub_device_secret).build()
  login_res = client.publish(login_req)
  ```

3. Send telemetries from the MQTT client
  ```python
  meapt_req = MeasurepointPostRequest.builder() \
          .setProductKey(sub_product_key).setDeviceKey(sub_device_key) \
          .addMeasurePoint('MeasurePoint1', value1) \      # the measure point identity
          .addMeasurePoint('MeasurePoint2', value2) \
          .setTimestamp(timestamp) \
          .build()
  meapt_res = client.publish(meapt_req)
  ```

### End-to-End Sample

```python
from message.upstream.status.SubDeviceLoginRequest import SubDeviceLoginRequest
from core.MqttClient import MqttClient
from message.upstream.topo.TopoAddRequest import TopoAddRequest
from message.upstream.topo.SubDeviceInfo import SubDeviceInfo
from message.upstream.tsl.MeasurepointPostRequest import MeasurepointPostRequest
from message.upstream.topo.TopoGetRequest import TopoGetRequest
from message.upstream.topo.TopoDeleteRequest import TopoDeleteRequest
import random
import time

# mqtt broker url
enos_mqtt_url = "tcp://{HOST}:11883" # for tcp connection

# gateway parameters
gateway_product_key = "GATEWAY_PRODUCT_KEY"
gateway_product_secret = 'GATEWAY_PRODUCT_SECRET'
gateway_device_key = "GATEWAY_DEVICE_KEY"
gateway_device_secret = "GATEWAY_DEVICE_SECRET"

# sub-device parameters
sub_product_key = 'SUB_PRODUCT_KEY'
sub_device_key = "SUB_DEVICE_KEY"
sub_device_secret = "SUB_DEVICE_SECRET"

# these file are generated by get_cert.py via EnOS cert tool, for tls connection
ca_file = 'edge_ca.pem'
key_file = 'edge.key'
cer_file = 'edge.pem'
key_file_password = 'PRIVATE_KEY_PASSWORD'


def onOnline():
    print('connected...')


def onOffine():
    print('disconnected...')


def get_topo(mqtt_client):
    topo_get_req = TopoGetRequest.builder().build()
    topo_get_res = mqtt_client.publish(topo_get_req)
    print('topo_response: code: %s' % topo_get_res.getCode())
    print(topo_get_res.getData())


def add_topo(mqtt_client):
    topo_req = TopoAddRequest.builder().addSubDevice(SubDeviceInfo(sub_product_key, sub_device_key, sub_device_secret)).build()
    topo_res = mqtt_client.publish(topo_req)
    print('topo_response: code: %s' % topo_res.getCode())
    print('topo_response: message: %s' % topo_res.getMessage())


def delete_topo(mqtt_client):
    topo_del_req = TopoDeleteRequest.builder().addSubDevice(sub_product_key, sub_device_key).build()
    topo_del_res = mqtt_client.publish(topo_del_req)
    print('topo_delete_response: %s' % topo_del_res.getCode())


def login_sub_device(mqtt_client):
    login_req = SubDeviceLoginRequest.builder().setSubDeviceInfo(sub_product_key, sub_device_key, sub_device_secret).build()
    login_res = mqtt_client.publish(login_req)
    print('login_response: code: %s' % login_res.getCode())
    print('login_response: message: %s' % login_res.getMessage())


# post measure points data via MQTT
def post_measure_points(mqtt_client, timestamp):
    meapt_req = MeasurepointPostRequest.builder() \
        .setProductKey(sub_product_key).setDeviceKey(sub_device_key) \
        .addMeasurePoint('MeasurePoint1', random.randint(100, 200)) \
        .addMeasurePoint('MeasurePoint2', random.randint(100, 200)) \
        .setTimestamp(timestamp) \
        .build()
    meapt_res = mqtt_client.publish(meapt_req)
    print('measurepointPost_response: %s' % meapt_res.getCode())

# handle the received downstream message and implement your logic
def handle_msg(arrivedMessage, replyHandler):
    '''
    :param arrivedMessage: <attributes:deviceKey,prodectKey,id,messageTopic,method,params,version>
    :param replyHandler: <method:replyWithPayload>
    '''
    # handle logic
    success = 1
    print(arrivedMessage.params)
    # set reply payload
    if success:
        code = 200
        message = 'test'
        data = 0
    else:
        code = 2000
        message = 'test'
        data = 1
    replyHandler.reply_with_payload(code=code, message=message, data=data)


if __name__ == "__main__":

    client = MqttClient(enos_mqtt_url, gateway_product_key, gateway_device_key, gateway_device_secret)
    # set the certificate files for bi-directional certification
    # client.getProfile().setSSLContext(ca_file, cer_file, key_file, key_file_password)
    client.setupBasicLogger('INFO')
    client.onOnline = onOnline
    client.onOffline = onOffine
    client.connect()                                # connect in sync

    client.onMessage(handle_msg)                    # register the handle_msg
    set_measure_points(client)                      #set a handler to recive the downstream measurepoint
    add_topo(client)                                # add the device to the gateway as sub-device
    login_sub_device(client)                        # login the sub-device
    while True:
        timestamp = int(time.time() * 1000)        # timestamp in milliseconds
        post_measure_points(client, timestamp)     # publish measure points data
        time.sleep(10)

```


