Skip to main content

Murano Device Client is the primary library for communicating with the Exosite Murano Platform.

Project description

A library for quickly testing, evaluating and writing client software for Murano devices.

Supported features:

  • HTTPS Device API

  • MQTT Device API

  • TOKEN Auth

  • TLS Client Cert Auth

  • Command Line Interface (gdc --help)

Requirements

  • Python 3.5+

  • paho-mqtt (>=1.3.1)

  • requests (>=2.13.0)

  • docopt (>=0.6.2)

  • six

Installation

Run the following command.

> pip install murano-client

HTTP CLI Examples

Timestamp

> gdc -H https://t41hp23nod8s00000.m2.exosite.io/ http timestamp
1527272454

Activate

> gdc -H https://t41hp23nod8s00000.m2.exosite.io/ -u myDeviceName-1 http activate
97eWgtm9Et5VxwuJT8NiOK7w27Ly2GS092oSxgpW

Write

> gdc -H https://t41hp23nod8s00000.m2.exosite.io/ -k 97eWgtm9Et5VxwuJT8NiOK7w27Ly2GS092oSxgpW http write data_in '{"some": "json data"}'
[204] No content

Record

> gdc -H https://t41hp23nod8s00000.m2.exosite.io/ -k 97eWgtm9Et5VxwuJT8NiOK7w27Ly2GS092oSxgpW http record $(date +%s) data_in '{"historical": "data"}'
[204] No content

Read

> gdc -H https://t41hp23nod8s00000.m2.exosite.io/ -k 97eWgtm9Et5VxwuJT8NiOK7w27Ly2GS092oSxgpW http read data_in
data_in={"historical": "data"}

Poll

> gdc  -H 'https://t41hp23nod8s00000.m2.exosite.io/' -k 97eWgtm9Et5VxwuJT8NiOK7w27Ly2GS092oSxgpW http poll config_io 3000
[304] Not modified
> gdc  -H 'https://t41hp23nod8s00000.m2.exosite.io/' -k 97eWgtm9Et5VxwuJT8NiOK7w27Ly2GS092oSxgpW http poll config_io 30000
[200] config_io={"some": "config data"}

Content

List Content

> gdc -H 'https://t41hp23nod8s00000.m2.exosite.io/' -k 97eWgtm9Et5VxwuJT8NiOK7w27Ly2GS092oSxgpW http content list
requests_check.v1.tar.gz
ota_bundle_test.v2.tar.gz
ota_bundle_test.v1.tar.gz
gwe.v1.5.RC68.tar.gz
gwe.v1.5.RC59.tar.gz
gwe.v1.5.RC58.tar.gz
gwe.v1.5.RC57.tar.gz

Get Content Info

> gdc -H 'https://t41hp23nod8s00000.m2.exosite.io/' -k 97eWgtm9Et5VxwuJT8NiOK7w27Ly2GS092oSxgpW http content info gwe.v1.5.RC68.tar.gz
application/gzip,691529,1513931066,

Download Content

> gdc -H 'https://t41hp23nod8s00000.m2.exosite.io/' -k 97eWgtm9Et5VxwuJT8NiOK7w27Ly2GS092oSxgpW http content download gwe.v1.5.RC68.tar.gz
WARNING:urllib3.response:Received response with both Content-Length and Transfer-Encoding set. This is expressly forbidden by RFC 7230 sec 3.3.2. Ignoring Content-Length and attempting to process response as Transfer-Encoding: chunked.
> file gwe.v1.5.RC68.tar.gz
gwe.v1.5.RC68.tar.gz: gzip compressed data, last modified: Fri Dec 22 08:24:23 2017, from Unix

MQTT CLI Examples

Activate

Activate a client with via MQTT.

> gdc -H mqtt://t41hp23nod8s00000.m2.exosite.io/ -u cleanup-stuff mqtt activate
oihLldO3f53dqyJYDmiRCijVsf4eQJeUxFSBnEsk

Publish

Publish a single payload with MQTT.

> gdc -H mqtt://t41hp23nod8s00000.m2.exosite.io/ -k oihLldO3f53dqyJYDmiRCijVsf4eQJeUxFSBnEsk mqtt publish \$resource/data_in "{\"time\": $(date +%s)}"
rc=0, mid=1: {"time": 1528214840}

Subscribe

Subscribe to a murano client.

NOTE: MQTT Subscribe works on all resources of a Murano client. Subscribing to a specific resource is not supported. Unsubscribe is also not supported.

> gdc -H mqtt://t41hp23nod8s00000.m2.exosite.io/ -k oihLldO3f53dqyJYDmiRCijVsf4eQJeUxFSBnEsk mqtt subscribe
update_interval.1528215003884000=60

Pubsub

Use this command to publish newline-delineated date to a client resource while simultaneously subscribing to its resources.

> while true
do
    echo "{\"time\": $(date +%s)}"
    sleep 0.5
done | gdc -H mqtt://t41hp23nod8s00000.m2.exosite.io/ \
           -k oihLldO3f53dqyJYDmiRCijVsf4eQJeUxFSBnEsk \
           mqtt pubsub \
           \$resource/config_io
update_interval.1528215003884000=60

Client Applications

For examples of how to import this library, see the commands in the murano_client/commands/ directory.

Simple HTTP Example Application

#!/usr/bin/env python

# example.py

import time
import uuid
import json
from murano_client.http import MuranoHTTP, Http_ReadWriteCodes

HTTP_TIMEOUT = 5*60*1000 # 5 minutes
config_io = None

client_params = {
    "murano_host": "https://t41hp23nod8s00000.m2.exosite.io/",
    "murano_id": str(uuid.uuid4()),
    "http_timeout": 5.0,
    "debug": "DEBUG",
}

print("Client parameters: {}".format(json.dumps(client_params)))

hc = MuranoHTTP(**client_params)
hc.set_http_timeout(HTTP_TIMEOUT)

while not hc.is_activated():
    hc.http_activate()
    print("TOKEN: {}".format(hc.murano_token()))
    if not hc.is_activated():
        time.sleep(HTTP_TIMEOUT)

print("Starting long poll...")

while True:
    response_handler = hc.http_long_poll(
            'config_io',
            HTTP_TIMEOUT,
            time.time()
        )

    if response_handler.code == Http_ReadWriteCodes.NotModified:
        print("no config_io yet...")
    elif response_handler.code == Http_ReadWriteCodes.OK:
        print(response_handler.body)
        config_io = json.loads(response_handler.body.strip("config_io="))
        print("got config_io: {}".format(config_io))
        hc.http_write('config_io', "ACK")
    else:
        print(response_handler)

    if config_io:
        print(hc.http_write('data_in', str(uuid.uuid4())))

Simple MQTT Example Application

#!/usr/bin/env python

# example.py
from __future__ import print_function
import time
import uuid
import json
from murano_client.mqtt import MuranoMQTT

client_params = {
    "murano_host": "mqtt://t41hp23nod8s00000.m2.exosite.io/",
    "murano_id": str(uuid.uuid4()),
    # "debug": "DEBUG",
}

print("Client parameters: {}".format(json.dumps(client_params)))

mc = MuranoMQTT(**client_params)
mc.start()

mc.Config_IO = None

print("Starting activation...")
if not mc.is_activated():
    mc.activate()
    print("TOKEN: {}".format(mc.murano_token()))

def on_message(cls, userdata, msg):
    """ Override default on_message function. """
    _, resource, timestamp = msg.topic.split('/')[0:3]
    print("{}.{}={}".format(resource, timestamp, msg.payload))
    if 'config_io' == resource:
        try:
            cls.Config_IO = json.loads(msg.payload.decode())
            print("New Config_IO: {}".format(cls.Config_IO))
        except ValueError:
            print("Invalid JSON: {}".format(msg.payload.decode()))
mc.on_message = on_message

print("Starting program...")

mc.start()

while True:

    if mc.Config_IO:
        rand_data = str(uuid.uuid4())
        rc, mid = mc.publish(
                             '$resource/data_in',
                             rand_data,
                             qos=0
                             )
        print("rc={}, mid={}, data={}"
              .format(rc, mid, rand_data))
    else:
        print("waiting for config_io object...")

    mc.loop()
    time.sleep(1)

Simple MuranoClient Client Applications

The MuranoClient class takes the following constructor parameters:

  • murano_host - Required. The application will use the appropriate protocol to communicate with Murano according to the Product settings.

  • murano_id - This is the device identifier (e.g. serial number, etc.).

  • watchlist - Provide a list of resources from which to be notified of when new data is available. NOTE: Currently only one resource is supported.

  • http_timeout - Specify the length of time in between Long Poll connections when using HTTP.

  • debug - Turn the logging up or down. Valid values are the string values DEBUG, INFO, WARNING, ERROR and CRITICAL.

The application, below, uses the MuranoClient class’s MQTT option to “echo” payloads from the config_io resource to the data_in resource.

#!/usr/bin/env python

import sys
import signal
import time
from murano_client.client import MuranoClient

c = MuranoClient(
    murano_host='mqtt://t41hp23nod8s00000.m2.exosite.io/',
    murano_id=sys.argv[1],
    watchlist=['config_io'],
    http_timeout=5*60,
    debug='DEBUG')

def stop(signal, frame):
    print("stopping")
    c.stop_all()
    sys.exit(0)

signal.signal(signal.SIGINT, stop)

c.client_activate()
c.start_client()

while True:
    data_from_murano = c.watch()
    if data_from_murano:
        c.tell(
            resource='data_in',
            timestamp=time.time(),
            payload=data_from_murano.payload
        )

The example below uses the HTTP option to periodically write the current time into the data_in resource.

IMPORTANT:

#!/usr/bin/env python

import sys
import signal
import time
from murano_client.client import MuranoClient

c = MuranoClient(
    murano_host='https://t41hp23nod8s00000.m2.exosite.io/',
    murano_id=sys.argv[1],
    watchlist=['config_io'],
    http_timeout=5,
    debug='DEBUG'
)

def stop(signal, frame):
    c.stop_all()
    sys.exit(0)

signal.signal(signal.SIGINT, stop)

c.client_activate()
c.start_client()

while True:
    c.tell(
        resource='data_in',
        timestamp=time.time(),
        payload='chirp: {}'.format(time.time())
    )
    print(c.watch(timeout=1.0))

INI State File

Required:

  • murano_host

  • murano_id

  • watchlist - comma delineated list of Murano resources

Optional:

  • murano_port - (https default: 443, mqtt default: 8883)

  • debug

  • murano_token

Example INI files:

##NOTE:## If client hasn’t provisioned yet, exclude murano_token. The Device class will set/save it after it activates.

# device.ini
[device]
murano_host = mqtt://t41hp23nod8s00000.m2.exosite.io/
murano_id = 4321
murano_port = 443
watchlist = config_io
debug = DEBUG
murano_token = XaFfMaOvrGxJgWk2Iftgw1cplYuZeSsUoKlKn0lb

Example application code that used the INI example, above.

#!/usr/bin/env python

from murano_client.ini import Device

d = Device('device.ini')
d.client_activate()
d.start_client()
print(d.watch()) # now set a value in the watchlist

Example CLI commands that use the INI file, above.

gdc -f device.ini http timestamp
gdc -f device.ini http activate
gdc -f device.ini http read config_io
gdc -f device.ini http write data_in '{"a": "3.14"}'
gdc -f device.ini http record $(date +%s) data_in '{"a": "3.14"}'
gdc -f device.ini mqtt timestamp
gdc -f device.ini mqtt activate
gdc -f device.ini mqtt publish \$resource/data_in '{"a": "3.14"}'
gdc -f device.ini mqtt subscribe

Logging

The murano_client library has a log file rotator built in. It is utilized via system environment variables only. It supports the following parameters:

  • MURANO_CLIENT_DEBUG - case-insensitive, default:warning (debug|info|warning|error|critical).

  • MURANO_CLIENT_LOGFILE - case-sensitive, default:stderr, can override to stdout or any file path.

  • MURANO_CLIENT_LOG_MAX_BYTES - integer(bytes), default:1024000

  • MURANO_CLIENT_MAX_BACKUPS - integer(number-of-backups), default:3

export MURANO_CLIENT_DEBUG=debug
export MURANO_CLIENT_LOGFILE=/var/log/murano_client.log
export MURANO_CLIENT_LOG_MAX_BYTES=$((1024*100))
export MURANO_CLIENT_MAX_BACKUPS=2

NOTE: Any application (e.g. edged) can override the MURANO_CLIENT_DEBUG parameter during runtime with the debug=<level> keyword argument to MuranoClient objects.

Test

To execute tests:

> export MURANO_HOST https://x28f1bttwbtzw0000.m2.exosite.io/
> pip install -U tox
> tox

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

murano_client-21.12.22-py2.py3-none-any.whl (54.7 kB view hashes)

Uploaded Python 2 Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page