Xively: how to activate a device with the python api?

徘徊边缘 提交于 2019-12-11 13:46:35

问题


Since COSM has become Xively, a nice device api has been added (or was always there- not sure). The flow is

  1. create product batch with serial numbers
  2. activate devices using some product batch identifiers (?)
  3. start using the device with the obtained feed/api keys

I can't figure out how to do this via the python API- are there any pointers?


回答1:


This should be added to the library, but for now you can use this code to implement device activation. I have used environment variables to store product secret and device serial, but change that for anything that suites your use case. The only tricky part is that you need to call a2b_hex().

import xively

from os import environ    
from hashlib import sha1
from binascii import a2b_hex
import hmac

secret = environ['XIVELY_PRODUCT_SECRET']
serial = environ['XIVELY_DEVICE_SERIAL_NUMBER']

activation = hmac.new(a2b_hex(secret), serial, sha1).hexdigest()

creds = xively.Client(key=None).get('/v2/devices/'+activation+'/activate').json()

xi_feed = xively.XivelyAPIClient(creds['apikey']).feeds.get(creds['feed_id'])

You will also need take care to store the credentials into a file, as a device can be activated only once. You will notice 403 errors if you try to run this code again and again, so do use the Xively developer workbench for deactivating the device under test (you may need to refresh the page).

Here is a fully working example using config files or environment variables:

#!/usr/bin/python

from os import environ 
from hashlib import sha1 
from binascii import a2b_hex 
import hmac
import sys, subprocess
import ConfigParser
import xively

CONFIG_FILE = 'xively.conf'

PROVISIONING = 'PROVISIONING'

PROVISIONING_PRODUCT_SECRET = 'PRODUCT_SECRET'
PROVISIONING_DEVICE_SERIAL = 'DEVICE_SERIAL'

PROVISIONING_FEED_ID = 'FEED_ID'
PROVISIONING_API_KEY = 'API_KEY'

def get_setting(config, section, key):
    try:
    value = config.get(section, key)
    except:
    print key + " not found in config file. Using environment variable " + key + " instead."

    try:
        value = environ[key]
    except:
        print key + " not found in environment."
        raise
    # value defined?
    if not value:
    raise
    return value

def xively_activate_product(secret, serial):
    activation = hmac.new(a2b_hex(secret), serial, sha1).hexdigest()
    creds = xively.Client(key=None).get('/v2/devices/'+activation+'/activate').json()
    return creds 

# main
config = ConfigParser.RawConfigParser()
config.read(CONFIG_FILE)

try:
    # see if we already have an api key and feed id
    feed_id = config.get(PROVISIONING, PROVISIONING_FEED_ID)
    api_key = config.get(PROVISIONING, PROVISIONING_API_KEY)

    print "Provisioned product details:"
    print "FEED_ID: " + str(feed_id)
    print "API_KEY: " + api_key

    # continue working with your activated product here

except:
    print "FEED_ID and API_KEY not found. Activating product now."

    # no error handling for secret- it _is_ needed
    try:
    secret = get_setting(config, PROVISIONING, PROVISIONING_PRODUCT_SECRET)
    except:        
    print "Finding " + PROVISIONING_PRODUCT_SECRET + " failed. Giving up."
    sys.exit(1)

    try:
    serial = get_setting(config, PROVISIONING, PROVISIONING_DEVICE_SERIAL)
    except:        
    serial = subprocess.check_output("hostname", shell=True)
    if not serial:
        print "Fallback to hostname for " + PROVISIONING_DEVICE_SERIAL + " failed. Giving up."
        sys.exit(1)

    try:    
    creds = xively_activate_product(secret, serial)

    # check if there were errors
    try:
        creds["errors"]
    except:
        pass
    else:
        print "Product activation failed (" + creds["title"] +": "+ creds["errors"] + ")."
        sys.exit(1)

    feed_id = creds['feed_id']
    api_key = creds['apikey']

    print "Product activation successful."
    print "FEED_ID: " + str(feed_id)
    print "API_KEY: " + api_key

    if not config.has_section(PROVISIONING):
        config.add_section(PROVISIONING)

    config.set(PROVISIONING, PROVISIONING_FEED_ID, feed_id)
    config.set(PROVISIONING, PROVISIONING_API_KEY, api_key)

    # Writing our configuration file to 'example.cfg'
    with open(CONFIG_FILE, 'wb') as configfile:
        config.write(configfile)

    except Exception as e:
    print "Product activation failed (" + str(e) +")."
    sys.exit(1)



回答2:


This is another helpful class I wrote:

## Logging for debugging purposes
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


import os
from os import environ 
from hashlib import sha1 
from binascii import a2b_hex 
import hmac
import sys, subprocess
import ConfigParser
import xively


PROVISIONING = 'PROVISIONING'

PROVISIONING_PRODUCT_SECRET = 'PRODUCT_SECRET'

PROVISIONING_FEED_ID = 'FEED_ID'
PROVISIONING_API_KEY = 'API_KEY'


class XivelyManager:

    def __init__(self, settings="xively.conf"):
        # main
        self.settings=settings
        self.config = ConfigParser.RawConfigParser()
        self.config.read(settings)

        try:
            # see if we already have an api key and feed id

            self.api_key = self.get_setting(PROVISIONING, PROVISIONING_API_KEY)
            self.secret = self.get_setting(PROVISIONING, PROVISIONING_PRODUCT_SECRET)
            # continue working with your activated product here

        except:
            logger.exception( "API KEY and SECRET NOT FOUND" )

    def activate_sensor(self,serial):

            try:    
                creds = self.xively_activate_product(str(serial))

                # check if there were errors
                try:
                    creds["errors"]
                except:
                    pass
                else:
                    logger.exception("Product activation failed (" + creds["title"] +": "+ creds["errors"] + ").")
                    return False

                feed_id = creds['feed_id']
                api_key = creds['apikey']

                if not self.config.has_section(PROVISIONING):
                    self.config.add_section(PROVISIONING)

                if not self.config.has_section(str(serial)):
                    self.config.add_section(str(serial))

                self.config.set(PROVISIONING, PROVISIONING_API_KEY, api_key)
                self.config.set(str(serial), PROVISIONING_FEED_ID , feed_id)

                # Writing our configuration file to 'xively.cfg'
                with open(self.settings, 'wb') as configfile:
                    self.config.write(configfile)
                return True

            except Exception as e:
                logger.exception("Product activation failed (" + str(e) +").")
                return False

    def get_setting(self, section, key):
        try:

            value = self.config.get(section, key)
        except:
            logger.exception( key + " not found in config file. Using environment variable " + key + " instead.")
##            try:
##                value = environ[key]
##            except:
##                logger.exception( key + " not found in environment.")
##            finally:
##                pass
        finally:

            # value defined?
            if not value:
                raise
            return value

    def get_feed(self,serial):
        try:
            if self.config.has_section(str(serial)):
                feed_id = self.get_setting(str(serial), PROVISIONING_FEED_ID)
            else:
                feed_id=False
        except Exception, e:
            feed_id=False
        finally:
            return feed_id

    def xively_activate_product(self, serial):
        activation = hmac.new(a2b_hex(self.secret), serial, sha1).hexdigest()
        creds = xively.Client(key=None).get('/v2/devices/'+activation+'/activate').json()
        return creds 

if __name__ == "__main__":
    print "Testing Xively Manager "
    settings = os.path.join(os.path.dirname(sys.argv[0]), "config", "xively.conf")
    print settings

    testxive=XivelyManager(settings)
    #print testxive.activate_sensor(10)

    print testxive.get_feed(10)

This is helpful when your internet gateway is connected to several other devices. Your config file will be updated with stuff like this:

[PROVISIONING]
product_secret = xxxxxxxxxxxxxxxxxxxxxxxxxxxx
api_key = xxxxxxxxxxxxxxxxxxxxxxxx

[productserial1]
feed_id = xxxxxxxx

[productserial2]
feed_id = xxxxxxxx


来源:https://stackoverflow.com/questions/17250056/xively-how-to-activate-a-device-with-the-python-api

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!