Example #1
0
    def add_collection(self, path, *args): 
        """Add collection to the namespace.  For instance::

          inst.add_collection('/c1')

        :param string path: path under which to add the collection
        :param args[0]: :py:class:`Collection` class to add, if present
        :rtype: the :py:class:`Collection` which was added
        :raises: :py:class:`SmapException` if the parent is not a
         collection, or the path exists.
"""
        if len(args) > 0 and ICollection.providedBy(args[0]):
            collection = args[0]
        elif len(args) == 0:
            collection = Collection(path, self)
        else:
            raise SmapException("add_collection: wrong number of arguments")

        path = util.split_path(path)
        if len(path) > 0:
            parent = self.get_collection(util.join_path(path[:-1]))
            if not parent:
                raise SmapException("add_collection: parent is not collection!")
            parent.add_child(path[-1])
        if util.join_path(path) in self.OBJS_PATH:
            raise SmapException("add_timeseries: path " + str(path) + 
                                " exists!")

        self.OBJS_PATH[util.join_path(path)] = collection
        if not self.loading: self.reports.update_subscriptions()
        return collection
Example #2
0
    def add_collection(self, path, *args):
        """Add collection to the namespace.  For instance::

          inst.add_collection('/c1')

        :param string path: path under which to add the collection
        :param args[0]: :py:class:`Collection` class to add, if present
        :rtype: the :py:class:`Collection` which was added
        :raises: :py:class:`SmapException` if the parent is not a
         collection, or the path exists.
"""
        if len(args) > 0 and ICollection.providedBy(args[0]):
            collection = args[0]
        elif len(args) == 0:
            collection = Collection(path, self)
        else:
            raise SmapException("add_collection: wrong number of arguments")

        path = util.split_path(path)
        if len(path) > 0:
            parent = self.get_collection(util.join_path(path[:-1]))
            if not parent:
                raise SmapException(
                    "add_collection: parent is not collection!")
            parent.add_child(path[-1])
        if util.join_path(path) in self.OBJS_PATH:
            raise SmapException("add_timeseries: path " + str(path) +
                                " exists!")

        self.OBJS_PATH[util.join_path(path)] = collection
        if not self.loading: self.reports.update_subscriptions()
        return collection
Example #3
0
    def add_timeseries(self, path, *args, **kwargs):
        """Add a timeseries to the smap server at the given path.  This will
        generate a UUID for the timeseries.

        direct form 
        :param path a Timeseries instance
        
        simple form 
        :param args[0] is a uuid instance, or a key to generate a uuid with by combining it with the root uuid.
        :param args[1] and kwargs are arguments passed to the Timeseries constructor.  Therefore you have to include at least the UnitofMeasure

        :param boolean replace: (kwarg) replace an existing timeseries at that path instead of throwing an exception
        :param boolean recurse: recursively create parent collections instead of thrwoing an exception.  Default is True.

        :raises: :py:class:`SmapException` if the parent isn't a collection or the path already exists.
        """ 
        replace = kwargs.pop('replace', False)
        recurse = kwargs.pop('recurse', True)
        klass = kwargs.pop('klass', Timeseries)

        if len(args) == 0 or \
                not ITimeseries.providedBy(args[0]) and not IActuator.providedBy(args[0]):
            if len(args) == 2:
                if not isinstance(args[0], uuid.UUID):
                    id = self.uuid(args[0], namespace=kwargs.get('namespace', None))
                else:
                    id = args[0]
                args = args[1:]
            elif len(args) == 1:
                id = self.uuid(util.norm_path(path), kwargs.get('namespace', None))
            else:
                id = self.uuid(util.norm_path(path))
#                 raise SmapException("SmapInstance.add_timeseries may only be called "
#                                     "with two or three arguments")

            kwargs.pop('namespace', None)
            timeseries = klass(id, *args, **kwargs)
            if id != args[0]:
                setattr(timeseries, "key", args[0])
        else:
            timeseries = args[0]

        path = util.split_path(path)
        if recurse: self._add_parents(path)
        parent = self.get_collection(util.join_path(path[:-1]))

        if not replace and util.join_path(path) in self.OBJS_PATH:
            raise SmapException("add_timeseries: path " + str(path) + " exists!")
        if not parent:
            raise SmapException("add_timeseries: parent is not a collection!")
        parent.add_child(path[-1])

        # place the new timeseries into the uuid and path tables
        self.OBJS_UUID[timeseries['uuid']] = timeseries
        self.OBJS_PATH[util.join_path(path)] = timeseries
        timeseries.inst = self
        setattr(timeseries, 'path', util.join_path(path))
        if not self.loading: self.reports.update_subscriptions()
        return timeseries
Example #4
0
    def add_timeseries(self, path, *args, **kwargs):
        """Add a timeseries to the smap server at the given path.  This will
        generate a UUID for the timeseries.

        direct form 
        :param path a Timeseries instance
        
        simple form 
        :param args[0] is a uuid instance, or a key to generate a uuid with by combining it with the root uuid.
        :param args[1] and kwargs are arguments passed to the Timeseries constructor.  Therefore you have to include at least the UnitofMeasure

        :param boolean replace: (kwarg) replace an existing timeseries at that path instead of throwing an exception
        :param boolean recurse: recursively create parent collections instead of thrwoing an exception.  Default is True.

        :raises: :py:class:`SmapException` if the parent isn't a collection or the path already exists.
        """ 
        replace = kwargs.pop('replace', False)
        recurse = kwargs.pop('recurse', True)
        klass = kwargs.pop('klass', Timeseries)
        if len(args) == 0 or \
                not ITimeseries.providedBy(args[0]) and not IActuator.providedBy(args[0]):
            if len(args) == 2:
                if not isinstance(args[0], uuid.UUID):
                    id = self.uuid(args[0], namespace=kwargs.get('namespace', None))
                else:
                    id = args[0]
                args = args[1:]
            elif len(args) == 1:
                id = self.uuid(util.norm_path(path), kwargs.get('namespace', None))
            else:
                id = self.uuid(util.norm_path(path))
#                 raise SmapException("SmapInstance.add_timeseries may only be called "
#                                     "with two or three arguments")

            kwargs.pop('namespace', None)
            timeseries = klass(id, *args, **kwargs)
            if id != args[0]:
                setattr(timeseries, "key", args[0])
        else:
            timeseries = args[0]

        path = util.split_path(path)
        if recurse: self._add_parents(path)
        parent = self.get_collection(util.join_path(path[:-1]))

        if not replace and util.join_path(path) in self.OBJS_PATH:
            raise SmapException("add_timeseries: path " + str(path) + " exists!")
        if not parent:
            raise SmapException("add_timeseries: parent is not a collection!")
        parent.add_child(path[-1])

        # place the new timeseries into the uuid and path tables
        self.OBJS_UUID[timeseries['uuid']] = timeseries
        self.OBJS_PATH[util.join_path(path)] = timeseries
        timeseries.inst = self
        setattr(timeseries, 'path', util.join_path(path))
        if not self.loading: self.reports.update_subscriptions()
        return timeseries
Example #5
0
 def explore(item, path):
     if not 'Contents' in item:
         item.dirty = True
     else:
         for ps in item['Contents']:
             newpath = path + [ps]
             explore(self.inst.lookup(util.join_path(newpath)), newpath)
Example #6
0
class InstanceResource(resource.Resource):
    """Resource which maps HTTP requests to requests on the sMAP
    instance.
    """
    def __init__(self, inst):
        self.inst = inst
        resource.Resource.__init__(self)

    isLeaf = True

    def render_GET(self, request):
        request.setHeader('Content-type', 'application/json')
        # assemble the results
        try:
            obj = self.inst.lookup(util.join_path(request.postpath))
        except Exception, e:
            import traceback
            traceback.print_exc()
            setResponseCode(request, exception, 500)
            request.finish()

        if obj == None:
            request.setResponseCode(404)
            return ("No such timeseries or collection: " +
                    util.join_path(request.postpath) + '\n')
        else:
            d = defer.maybeDeferred(core.SmapInstance.render_lookup, request,
                                    obj)
            d.addCallback(lambda x: self.send_reply(request, x))
            d.addErrback(lambda x: self.send_error(request, x))
            return server.NOT_DONE_YET
Example #7
0
 def explore(item, path):
     if not 'Contents' in item:
         item.dirty = True
     else:
         for ps in item['Contents']:
             newpath = path + [ps]
             explore(self.inst.lookup(util.join_path(newpath)), 
                     newpath)
Example #8
0
 def render_PUT(self, request):
     request.setHeader('Content-type', 'application/json')
     # you can only PUT actuators
     obj = self.inst.lookup(util.join_path(request.postpath))
     d = defer.maybeDeferred(core.SmapInstance.render_lookup, request, obj)
     d.addCallback(lambda x: self.send_reply(request, x))
     d.addErrback(lambda x: self.send_error(request, x))
     return server.NOT_DONE_YET
Example #9
0
File: server.py Project: ahaas/smap
 def render_PUT(self, request):
     request.setHeader('Content-type', 'application/json')
     # you can only PUT actuators
     obj = self.inst.lookup(util.join_path(request.postpath))
     d = defer.maybeDeferred(core.SmapInstance.render_lookup, request, obj)
     d.addCallback(lambda x: self.send_reply(request, x))
     d.addErrback(lambda x: self.send_error(request, x))
     return server.NOT_DONE_YET
Example #10
0
File: server.py Project: ahaas/smap
 def render_GET(self, request):
     request.setHeader('Content-type', 'application/json')
     # assemble the results
     try:
         obj = self.inst.lookup(util.join_path(request.postpath))
     except Exception, e:
         import traceback
         traceback.print_exc()
         setResponseCode(request, exception, 500)
         request.finish()
Example #11
0
 def render_GET(self, request):
     request.setHeader('Content-type', 'application/json')
     # assemble the results
     try:
         obj = self.inst.lookup(util.join_path(request.postpath))
     except Exception, e:
         import traceback
         traceback.print_exc()
         setResponseCode(request, exception, 500)
         request.finish()
Example #12
0
 def lookup(self, id, pred=None):
     """Retrieve an object in the resource hierarchy by path or uuid.  If
     *id* is a string not starting with ``/``, it will be passed to the
     :py:class:`uuid.UUID` constructor; otherwise it will be treated as a
     pathname.  *pred* is an optional predicate which can be used to test
     the result.
     """
     if util.is_string(id):
         path = util.split_path(id)
         if len(path) > 0 and path[-1][0] == "+":
             return self._lookup_r(util.join_path(path[:-1]), pred=pred)
         else:
             obj = self.OBJS_PATH.get(util.join_path(path), None)
     elif isinstance(id, uuid.UUID):
         return self.OBJS_UUID.get(id, None)
     else:
         obj = None
     
     if not pred or pred(obj):
         return obj
     else: return None
Example #13
0
 def lookup(self, id, pred=None):
     """Retrieve an object in the resource hierarchy by path or uuid.  If
     *id* is a string not starting with ``/``, it will be passed to the
     :py:class:`uuid.UUID` constructor; otherwise it will be treated as a
     pathname.  *pred* is an optional predicate which can be used to test
     the result.
     """
     if util.is_string(id):
         path = util.split_path(id)
         if len(path) > 0 and path[-1][0] == "+":
             return self._lookup_r(util.join_path(path[:-1]), pred=pred)
         else:
             obj = self.OBJS_PATH.get(util.join_path(path), None)
     elif isinstance(id, uuid.UUID):
         return self.OBJS_UUID.get(id, None)
     else:
         obj = None
     
     if not pred or pred(obj):
         return obj
     else: return None
Example #14
0
 def writeDROMScsv(self, value):
     fcsv = open('meterdata.csv','w')
     fcsv.write(','.join(['DateTime', 'MeterId', 'Value1', 'Value2']) + '\n')
     for path, val in value:
         if not 'Readings' in val: continue
         cmps = split_path(path)
         channel = join_path(cmps[1:])
         for d in val['Readings']:
             if d is None: continue
             ts = dtutil.strftime_tz(dtutil.ts2dt(d[0] / 1000), "%Y-%m-%d %H:%M", tzstr='Local')
             if ts is None: continue
             v = d[1] 
             if v is None: continue
             if val['Properties']['UnitofMeasure']=='Watts': v /= 1000.
             v /= 4. # approximate kWh
             fcsv.write(','.join([ts,channel,str(v)]) + '\n')
     fcsv.close()
Example #15
0
 def _add_parents(self, path):
     for i in xrange(0, len(path)):
         if not self.get_collection(util.join_path(path[:i])):
             self.add_collection(util.join_path(path[:i]))
Example #16
0
    def _add(self, *args):
        """Add a new reading to this timeseries.  This version must
only be called from the :py:mod:`twisted` main loop; *i.e.* from a
callback added with ``reactor.callFromThread()``

Can be called with 1, 2, or 3 arguments.  The forms are

* ``_add(value)``
* ``_add(time, value)``
* ``_add(time, value, seqno)``

:raises SmapException: if the value's type does not match the stream
 type, or was called with an invalid number of arguments.
        """
        seqno = None
        if len(args) == 1:
            time = util.now()
            if self.milliseconds: time *= 1000
            value = args[0]
        elif len(args) == 2:
            time, value = args
        elif len(args) == 3:
            time, value, seqno = args
        else:
            raise SmapException("Invalid add arguments: must be (value), "
                                "(time, value), or (time, value, seqno)")

        # note that we got data now
        self.inst.statslog.mark()

        time = int(time)
        if not self.milliseconds:
            time *= 1000

        if not self._check_type(value):
            raise SmapException("Attempted to add " + str(value) + 
                                " to Timeseries, but " +
                                "the timeseries type is " + 
                                self.__getitem__('Properties')['ReadingType'])
        
        if seqno: reading = time, value, seqno
        else: reading = time, value
        self["Readings"].append(reading)
        if not hasattr(self, 'inst'): return

        # if a timeseries is dirty, we need to republish all of its
        # metadata before we publish it so stream is right. some of
        # this may have already been published, in which case it won't
        # actually do anything.
        if self.dirty:
            split_path = util.split_path(getattr(self, 'path'))
            for i in xrange(0, len(split_path)):
                path_seg = util.join_path(split_path[:i])
                self.inst.reports.publish(path_seg, 
                                          self.inst.get_collection(path_seg))
            rpt = dict(self)
            rpt['Readings'] = [reading]
            self.inst.reports.publish(getattr(self, 'path'), rpt)
            self.dirty = False
        else:
            # publish a stripped-down Timeseries object
            self.inst.reports.publish(getattr(self, 'path'),
                                      {'uuid' : self['uuid'],
                                       'Readings' : [reading]})
Example #17
0
 def _add_parents(self, path):
     for i in xrange(0, len(path)):
         if not self.get_collection(util.join_path(path[:i])):
             self.add_collection(util.join_path(path[:i]))
Example #18
0
    def _add(self, *args):
        """Add a new reading to this timeseries.  This version must
only be called from the :py:mod:`twisted` main loop; *i.e.* from a
callback added with ``reactor.callFromThread()``

Can be called with 1, 2, or 3 arguments.  The forms are

* ``_add(value)``
* ``_add(time, value)``
* ``_add(time, value, seqno)``

:raises SmapException: if the value's type does not match the stream
 type, or was called with an invalid number of arguments.
        """
        seqno = None
        if len(args) == 1:
            time = util.now()
            if self.milliseconds: time *= 1000
            value = args[0]
        elif len(args) == 2:
            time, value = args
        elif len(args) == 3:
            time, value, seqno = args
        else:
            raise SmapException("Invalid add arguments: must be (value), "
                                "(time, value), or (time, value, seqno)")

        # note that we got data now
        self.inst.statslog.mark()

        time = int(time)
        if not self.milliseconds:
            time *= 1000

        if not self._check_type(value):
            raise SmapException("Attempted to add " + str(value) +
                                " to Timeseries, but " +
                                "the timeseries type is " +
                                self.__getitem__('Properties')['ReadingType'])

        if seqno: reading = time, value, seqno
        else: reading = time, value
        self["Readings"].append(reading)
        if not hasattr(self, 'inst'): return

        # if a timeseries is dirty, we need to republish all of its
        # metadata before we publish it so stream is right. some of
        # this may have already been published, in which case it won't
        # actually do anything.
        if self.dirty:
            split_path = util.split_path(getattr(self, 'path'))
            for i in xrange(0, len(split_path)):
                path_seg = util.join_path(split_path[:i])
                self.inst.reports.publish(path_seg,
                                          self.inst.get_collection(path_seg))
            rpt = dict(self)
            rpt['Readings'] = [reading]
            self.inst.reports.publish(getattr(self, 'path'), rpt)
            self.dirty = False
        else:
            # publish a stripped-down Timeseries object
            self.inst.reports.publish(getattr(self, 'path'), {
                'uuid': self['uuid'],
                'Readings': [reading]
            })