示例#1
0
    def __init__(self, uri: URIRef, config: Graph, masterGraph: PatchableGraph,
                 mqtt, internalMqtt, debugPageData):
        self.uri = uri
        self.config = config
        self.masterGraph = masterGraph
        self.debugPageData = debugPageData
        self.mqtt = mqtt  # deprecated
        self.internalMqtt = internalMqtt

        self.mqttTopic = self.topicFromConfig(self.config)
        log.debug(f'new mqttTopic {self.mqttTopic}')

        self.debugSub = {
            'topic': self.mqttTopic.decode('ascii'),
            'recentMessages': [],
            'recentParsed': [],
            'recentConversions': [],
            'currentMetrics': [],
            'currentOutputGraph': {
                't': 1,
                'n3': "(n3)"
            },
        }
        self.debugPageData['subscribed'].append(self.debugSub)

        rawBytes: Observable = self.subscribeMqtt(self.mqttTopic)
        # rawBytes = rx.operators.do_action(self.countIncomingMessage)(rawBytes)
        rawBytes.subscribe(on_next=self.countIncomingMessage)
示例#2
0
    def poll(self):
        ret = None
        startTime = time.time()
        try:
            url = (f'http://{deviceIp}/cgi-bin/cgi_manager').encode('ascii')
            resp = yield fetch(
                url,
                method=b'POST',
                headers={b'Authorization': [b'Basic %s' % auth]},
                postdata=(f'''<LocalCommand>
                              <Name>get_usage_data</Name>
                              <MacId>0x{macId}</MacId>
                            </LocalCommand>
                            <LocalCommand>
                              <Name>get_price_blocks</Name>
                              <MacId>0x{macId}</MacId>
                            </LocalCommand>''').encode('ascii'),
                timeout=10)
            ret = json.loads(resp.body)
            log.debug(ret)
            if ret['demand_units'] != 'kW':
                raise ValueError
            if ret['summation_units'] != 'kWh':
                raise ValueError
            pts = [
                dict(measurement='housePowerW',
                     fields=dict(value=float(ret['demand']) * 1000),
                     tags=dict(house='berkeley'),
                     time=int(startTime))]
            sd = float(ret['summation_delivered'])
            if sd > 0: # Sometimes nan
                pts.append(dict(measurement='housePowerSumDeliveredKwh',
                                fields=dict(value=float()),
                                tags=dict(house='berkeley'),
                                time=int(startTime)))
            if 'price' in ret:
                pts.append(dict(
                    measurement='price',
                    fields=dict(price=float(ret['price']),
                                price_units=float(ret['price_units'])),
                    tags=dict(house='berkeley'),
                    time=int(startTime),
                ))

            self.influx.write_points(pts, time_precision='s')

            self.graph.patchObject(context=ROOM['powerEagle'],
                                         subject=ROOM['housePower'],
                                         predicate=ROOM['instantDemandWatts'],
                                         newObject=Literal(float(ret['demand']) * 1000))
        except Exception as e:
            traceback.print_exc()
            log.error("failed: %r", e)
            log.error(repr(ret))
            os.abort()

        now = time.time()
        goal = startTime + periodSec - .2
        reactor.callLater(max(1, goal - now), self.poll)
示例#3
0
    def updateQuads(self, newGraphs):
        newQuads = set.union(*newGraphs)
        g = graphFromQuads(newQuads)
        log.debug(f'{self.uri} update to {len(newQuads)} statements')

        self.influx.exportToInflux(newQuads)

        self.masterGraph.patchSubgraph(self.uri, g)
示例#4
0
 def _publish(self,
              topic: str,
              messageJson: object = None,
              message: str = None):
     log.debug(f'mqtt.publish {topic} {message} {messageJson}')
     if messageJson is not None:
         message = json.dumps(messageJson)
     self.settings.mqtt.publish(topic.encode('ascii'),
                                message.encode('ascii'))
示例#5
0
    def poll(self):
        ret = None
        startTime = time.time()
        try:
            url = (f'http://{deviceIp}/cgi-bin/cgi_manager').encode('ascii')
            resp = yield fetch(
                url,
                method=b'POST',
                headers={b'Authorization': [b'Basic %s' % auth]},
                postdata=(f'''<LocalCommand>
                              <Name>get_usage_data</Name>
                              <MacId>0x{macId}</MacId>
                            </LocalCommand>
                            <LocalCommand>
                              <Name>get_price_blocks</Name>
                              <MacId>0x{macId}</MacId>
                            </LocalCommand>''').encode('ascii'),
                timeout=10)
            ret = json.loads(resp.body)
            log.debug(f"response body {ret}")
            if ret['demand_units'] != 'kW':
                raise ValueError
            if ret['summation_units'] != 'kWh':
                raise ValueError

            demandW = float(ret['demand']) * 1000
            self.out['w'].set(demandW)

            sd = float(ret['summation_delivered'])
            if sd > 0:  # Sometimes nan
                self.out['kwh'].set(sd)

            if 'price' in ret:
                self.out['price'].set(float(ret['price']))

            self.graph.patchObject(context=ROOM['powerEagle'],
                                   subject=ROOM['housePower'],
                                   predicate=ROOM['instantDemandWatts'],
                                   newObject=Literal(demandW))
            POLL_SUCCESSES.inc()
        except Exception as e:
            POLL_ERRORS.inc()
            traceback.print_exc()
            log.error("failed: %r", e)
            log.error(repr(ret))

        now = time.time()
        goal = startTime + periodSec - .2
        reactor.callLater(max(1, goal - now), self.poll)
示例#6
0
    def replaceSourceStatements(self, source: SourceUri,
                                stmts: Sequence[Statement]):
        log.debug('replaceSourceStatements with %s stmts', len(stmts))
        newStmts = set(stmts)

        with self.postDeleteStatements() as garbage:
            for stmt, (sources, handlers) in self.table.items():
                if source in sources:
                    if stmt not in stmts:
                        sources.remove(source)
                        if not sources and not handlers:
                            garbage.add(stmt)
                else:
                    if stmt in stmts:
                        sources.add(source)
                newStmts.discard(stmt)

        self.applySourcePatch(source, Patch(addQuads=newStmts, delQuads=[]))
示例#7
0
    def addSseHandler(self, handler: PatchSink):
        log.info('addSseHandler %r %r', handler, handler.streamId)

        # fail early if id doesn't match
        sources = self._sourcesForHandler(handler)

        self.handlers.add(handler)

        for source in sources:
            if source not in self.clients and source != COLLECTOR:
                log.debug('connect to patch source %s', source)
                self._localStatements.setSourceState(source, ROOM['connect'])
                self.clients[source] = ReconnectingPatchSource(
                    source,
                    listener=lambda p, fullGraph, source=source: self._onPatch(
                        source, p, fullGraph),
                    reconnectSecs=10)
        log.debug('bring new client up to date')

        self._sendUpdatePatch(handler)
示例#8
0
    def updateQuads(self, newGraphs):
        newQuads = set.union(*newGraphs)
        g = graphFromQuads(newQuads)
        log.debug(f'{self.uri} update to {len(newQuads)} statements')

        for quad in newQuads:
            meas = quad[0].split('/')[-1]
            if meas.startswith('airQuality'):
                where_prefix, type_ = meas[len('airQuality'):].split('door')
                where = where_prefix + 'door'
                metric = 'air'
                tags = {'loc': where.lower(), 'type': type_.lower()}
                val = quad[2].toPython()
                if metric not in collectors:
                    collectors[metric] = Gauge(metric,
                                               'measurement',
                                               labelnames=tags.keys())

                collectors[metric].labels(**tags).set(val)

        self.masterGraph.patchSubgraph(self.uri, g)
示例#9
0
 def _sendUpdatePatch(self, handler: Optional[PatchSink] = None):
     """
     send a patch event out this handler to bring it up to date with
     self.statements
     """
     now = time.time()
     selected = self.handlers
     if handler is not None:
         if handler not in self.handlers:
             log.error("called _sendUpdatePatch on a handler that's gone")
             return
         selected = {handler}
     # reduce loops here- prepare all patches at once
     for h in selected:
         period = .9
         if 'Raspbian' in h.request.headers.get('user-agent', ''):
             period = 5
         if h.lastPatchSentTime > now - period:
             continue
         p = self.statements.makeSyncPatch(h,
                                           set(self._sourcesForHandler(h)))
         log.debug('makeSyncPatch for %r: %r', h, p.jsonRepr)
         if not p.isNoop():
             log.debug("send patch %s to %s", p.shortSummary(), h)
             # This can be a giant line, which was a problem
             # once. Might be nice for this service to try to break
             # it up into multiple sends, although there's no
             # guarantee at all since any single stmt could be any
             # length.
             h.sendEvent(message=jsonFromPatch(p).encode('utf8'),
                         event=b'patch')
             h.lastPatchSentTime = now
         else:
             log.debug('nothing to send to %s', h)
示例#10
0
        self.loop.stop()


if __name__ == '__main__':
    arg = docopt("""
    Usage: mqtt_to_rdf.py [options]

    -v        Verbose
    --cs=STR  Only process config filenames with this substring
    """)
    verboseLogging(arg['-v'])

    config = Graph()
    for fn in Path('.').glob('conf/*.n3'):
        if not arg['--cs'] or str(arg['--cs']) in str(fn):
            log.debug(f'loading {fn}')
            config.parse(str(fn), format='n3')
        else:
            log.debug(f'skipping {fn}')

    masterGraph = PatchableGraph()

    brokerHost = 'mosquitto-frontdoor.default.svc.cluster.local'
    brokerPort = 10210

    debugPageData = {
        # schema in index.ts
        'server': f'{brokerHost}:{brokerPort}',
        'messagesSeen': 0,
        'subscribed': [],
    }