diff light_bridge.py @ 0:5a77696c6dab

start
author drewp@bigasterisk.com
date Sun, 28 Jan 2024 15:32:18 -0800
parents
children 42a494b8ee1a
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/light_bridge.py	Sun Jan 28 15:32:18 2024 -0800
@@ -0,0 +1,110 @@
+"""
+replaces a lot of mqtt_to_rdf and rdf_to_mqtt
+"""
+import asyncio
+from dataclasses import dataclass
+from functools import partial
+import json
+import logging
+
+import background_loop
+from patchablegraph import PatchableGraph
+from patchablegraph.handler import GraphEvents, StaticGraph
+from rdflib import Namespace
+from starlette.applications import Starlette
+from starlette.requests import Request
+from starlette.responses import JSONResponse
+from starlette.routing import Route
+from starlette_exporter import PrometheusMiddleware, handle_metrics
+from sse_starlette.sse import EventSourceResponse
+
+EX = Namespace('http://example.com/')
+
+logging.basicConfig(level=logging.INFO)
+log = logging.getLogger()
+
+
+class Color(str):
+
+    def to_js(self):
+        return self
+
+
+@dataclass
+class Light:
+    name: str
+    address: str
+    online: bool
+    colorRequest: Color
+    colorMessage: dict
+    colorCurrent: Color
+    latencyMs: float
+
+    def to_js(self):
+        return {
+            'light': {
+                'name': self.name,
+                'address': self.address,
+                'online': self.online,
+                'colorRequest': self.colorRequest.to_js(),
+                'colorMessage': self.colorMessage,
+                'colorCurrent': self.colorCurrent.to_js(),
+                'latencyMs': self.latencyMs,
+            }
+        }
+
+
+class Lights:
+    _d: dict[str, Light] = {}
+
+    def add(self, d: Light):
+        self._d[d.name] = d
+
+    def byName(self, name: str) -> Light:
+        return self._d[name]
+
+    async def changes(self):  # yields None on any data change
+        while True:
+            yield None
+            await asyncio.sleep(1)
+
+    def to_js(self):
+        return {'lights': [d.to_js() for d in sorted(self._d.values(), key=lambda r: r.name)]}
+
+
+async def output(lights: Lights, request: Request) -> JSONResponse:
+    light = lights.byName(request.query_params['light'])
+    return JSONResponse(light.to_js())
+
+
+async def table(lights: Lights, req: Request) -> EventSourceResponse:
+
+    async def g():
+        async for ping in lights.changes():
+            yield json.dumps(lights.to_js())
+            await asyncio.sleep(1)
+
+    return EventSourceResponse(g())
+
+
+def main():
+    lights = Lights()
+    lights.add(Light('do-desk', 'topic1', True, Color('#ff0000'), {'r': 255}, Color('#000000'), 100))
+    lights.add(Light('do-desk2', 'topic2', True, Color('#ff00ff'), {'r': 255}, Color('#000000'), 200))
+    graph = PatchableGraph()
+    app = Starlette(debug=True,
+                    routes=[
+                        Route('/api/output', partial(output, lights), methods=['PUT']),
+                        Route('/api/table', partial(table, lights)),
+                        Route('/api/graph', StaticGraph(graph)),
+                        Route('/api/graph/events', GraphEvents(graph)),
+                    ])
+
+    app.add_middleware(PrometheusMiddleware, app_name='light-bridge')
+    app.add_route("/metrics", handle_metrics)
+    # app.state.loop = background_loop.loop_forever(lambda first_run=False: update(graph), 1)
+
+    return app
+
+
+app = main()